19630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown/*
29630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * Copyright (C) 2012 The Android Open Source Project
39630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown *
49630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * Licensed under the Apache License, Version 2.0 (the "License");
59630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * you may not use this file except in compliance with the License.
69630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * You may obtain a copy of the License at
79630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown *
89630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown *      http://www.apache.org/licenses/LICENSE-2.0
99630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown *
109630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * Unless required by applicable law or agreed to in writing, software
119630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * distributed under the License is distributed on an "AS IS" BASIS,
129630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * See the License for the specific language governing permissions and
149630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * limitations under the License.
159630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown */
169630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
179630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brownpackage com.android.server.power;
189630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
190449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopianimport java.io.PrintWriter;
200449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopianimport java.nio.ByteBuffer;
210449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopianimport java.nio.ByteOrder;
220449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopianimport java.nio.FloatBuffer;
237f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown
249630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brownimport android.graphics.PixelFormat;
250449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopianimport android.graphics.SurfaceTexture;
269630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brownimport android.opengl.EGL14;
279630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brownimport android.opengl.EGLConfig;
289630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brownimport android.opengl.EGLContext;
299630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brownimport android.opengl.EGLDisplay;
309630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brownimport android.opengl.EGLSurface;
319630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brownimport android.opengl.GLES10;
320449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopianimport android.opengl.GLES11Ext;
339630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brownimport android.os.Looper;
349630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brownimport android.util.FloatMath;
359630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brownimport android.util.Slog;
369630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brownimport android.view.Display;
379630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brownimport android.view.DisplayInfo;
38a86ab640f7bb0bf3cb4eaed80473ca8c5d131903Igor Murashkinimport android.view.Surface.OutOfResourcesException;
399630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brownimport android.view.Surface;
403866f0d581ceaa165710feeee9f37fe1b0d7067dMathias Agopianimport android.view.SurfaceControl;
419630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brownimport android.view.SurfaceSession;
429630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
430449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopianimport com.android.server.display.DisplayManagerService;
440449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopianimport com.android.server.display.DisplayTransactionListener;
459630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
469630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown/**
479630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * Bzzzoooop!  *crackle*
488b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown * <p>
499630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * Animates a screen transition from on to off or off to on by applying
509630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * some GL transformations to a screenshot.
518b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown * </p><p>
529630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * This component must only be created or accessed by the {@link Looper} thread
539630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * that belongs to the {@link DisplayPowerController}.
548b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown * </p>
559630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown */
569630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brownfinal class ElectronBeam {
579630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    private static final String TAG = "ElectronBeam";
589630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
599630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    private static final boolean DEBUG = false;
609630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
619630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    // The layer for the electron beam surface.
629630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    // This is currently hardcoded to be one layer above the boot animation.
639630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    private static final int ELECTRON_BEAM_LAYER = 0x40000001;
649630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
659630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    // The relative proportion of the animation to spend performing
669630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    // the horizontal stretch effect.  The remainder is spent performing
679630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    // the vertical stretch effect.
683c584f20ac8fe9378c094ad3b63936bca35954baJeff Brown    private static final float HSTRETCH_DURATION = 0.5f;
699630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    private static final float VSTRETCH_DURATION = 1.0f - HSTRETCH_DURATION;
709630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
7178eb122450f127d66d4e8cf7f65cad80ea85d3acJeff Brown    // The number of frames to draw when preparing the animation so that it will
7278eb122450f127d66d4e8cf7f65cad80ea85d3acJeff Brown    // be ready to run smoothly.  We use 3 frames because we are triple-buffered.
7378eb122450f127d66d4e8cf7f65cad80ea85d3acJeff Brown    // See code for details.
7478eb122450f127d66d4e8cf7f65cad80ea85d3acJeff Brown    private static final int DEJANK_FRAMES = 3;
7578eb122450f127d66d4e8cf7f65cad80ea85d3acJeff Brown
769630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    // Set to true when the animation context has been fully prepared.
779630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    private boolean mPrepared;
788b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown    private int mMode;
799630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
807f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown    private final DisplayManagerService mDisplayManager;
819630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    private int mDisplayLayerStack; // layer stack associated with primary display
829630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    private int mDisplayWidth;      // real width, not rotated
839630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    private int mDisplayHeight;     // real height, not rotated
849630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    private SurfaceSession mSurfaceSession;
853866f0d581ceaa165710feeee9f37fe1b0d7067dMathias Agopian    private SurfaceControl mSurfaceControl;
8686e1bc730570765355dc8789b5c6de6962a053ccMathias Agopian    private Surface mSurface;
877f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown    private NaturalSurfaceLayout mSurfaceLayout;
889630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    private EGLDisplay mEglDisplay;
899630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    private EGLConfig mEglConfig;
909630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    private EGLContext mEglContext;
919630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    private EGLSurface mEglSurface;
929630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    private boolean mSurfaceVisible;
93252c206984299d7ce91c27536cafe1bb2fb9628dJeff Brown    private float mSurfaceAlpha;
949630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
959630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    // Texture names.  We only use one texture, which contains the screenshot.
969630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    private final int[] mTexNames = new int[1];
979630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    private boolean mTexNamesGenerated;
98a86ab640f7bb0bf3cb4eaed80473ca8c5d131903Igor Murashkin    private final float mTexMatrix[] = new float[16];
999630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
1009630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    // Vertex and corresponding texture coordinates.
1019630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    // We have 4 2D vertices, so 8 elements.  The vertices form a quad.
1029630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    private final FloatBuffer mVertexBuffer = createNativeFloatBuffer(8);
1039630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    private final FloatBuffer mTexCoordBuffer = createNativeFloatBuffer(8);
1049630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
105252c206984299d7ce91c27536cafe1bb2fb9628dJeff Brown    /**
106252c206984299d7ce91c27536cafe1bb2fb9628dJeff Brown     * Animates an electron beam warming up.
107252c206984299d7ce91c27536cafe1bb2fb9628dJeff Brown     */
1088b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown    public static final int MODE_WARM_UP = 0;
109252c206984299d7ce91c27536cafe1bb2fb9628dJeff Brown
110252c206984299d7ce91c27536cafe1bb2fb9628dJeff Brown    /**
111252c206984299d7ce91c27536cafe1bb2fb9628dJeff Brown     * Animates an electron beam shutting off.
112252c206984299d7ce91c27536cafe1bb2fb9628dJeff Brown     */
1138b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown    public static final int MODE_COOL_DOWN = 1;
114252c206984299d7ce91c27536cafe1bb2fb9628dJeff Brown
115252c206984299d7ce91c27536cafe1bb2fb9628dJeff Brown    /**
116252c206984299d7ce91c27536cafe1bb2fb9628dJeff Brown     * Animates a simple dim layer to fade the contents of the screen in or out progressively.
117252c206984299d7ce91c27536cafe1bb2fb9628dJeff Brown     */
118252c206984299d7ce91c27536cafe1bb2fb9628dJeff Brown    public static final int MODE_FADE = 2;
1198b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown
1200449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopian
1217f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown    public ElectronBeam(DisplayManagerService displayManager) {
1227f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown        mDisplayManager = displayManager;
1239630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    }
1249630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
1259630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    /**
1269630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     * Warms up the electron beam in preparation for turning on or off.
1279630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     * This method prepares a GL context, and captures a screen shot.
1289630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     *
1298b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown     * @param mode The desired mode for the upcoming animation.
1309630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     * @return True if the electron beam is ready, false if it is uncontrollable.
1319630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     */
1328b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown    public boolean prepare(int mode) {
1339630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        if (DEBUG) {
1348b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown            Slog.d(TAG, "prepare: mode=" + mode);
1359630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        }
1369630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
1378b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown        mMode = mode;
1389630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
1397f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown        // Get the display size and layer stack.
1407f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown        // This is not expected to change while the electron beam surface is showing.
1417f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown        DisplayInfo displayInfo = mDisplayManager.getDisplayInfo(Display.DEFAULT_DISPLAY);
1427f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown        mDisplayLayerStack = displayInfo.layerStack;
1437f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown        mDisplayWidth = displayInfo.getNaturalWidth();
1447f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown        mDisplayHeight = displayInfo.getNaturalHeight();
1459630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
1469630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        // Prepare the surface for drawing.
1478b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown        if (!tryPrepare()) {
1489630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            dismiss();
1499630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            return false;
1509630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        }
1519630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
1528b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown        // Done.
1539630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        mPrepared = true;
15478eb122450f127d66d4e8cf7f65cad80ea85d3acJeff Brown
15578eb122450f127d66d4e8cf7f65cad80ea85d3acJeff Brown        // Dejanking optimization.
15678eb122450f127d66d4e8cf7f65cad80ea85d3acJeff Brown        // Some GL drivers can introduce a lot of lag in the first few frames as they
15778eb122450f127d66d4e8cf7f65cad80ea85d3acJeff Brown        // initialize their state and allocate graphics buffers for rendering.
15878eb122450f127d66d4e8cf7f65cad80ea85d3acJeff Brown        // Work around this problem by rendering the first frame of the animation a few
15978eb122450f127d66d4e8cf7f65cad80ea85d3acJeff Brown        // times.  The rest of the animation should run smoothly thereafter.
16078eb122450f127d66d4e8cf7f65cad80ea85d3acJeff Brown        // The frames we draw here aren't visible because we are essentially just
16178eb122450f127d66d4e8cf7f65cad80ea85d3acJeff Brown        // painting the screenshot as-is.
16278eb122450f127d66d4e8cf7f65cad80ea85d3acJeff Brown        if (mode == MODE_COOL_DOWN) {
16378eb122450f127d66d4e8cf7f65cad80ea85d3acJeff Brown            for (int i = 0; i < DEJANK_FRAMES; i++) {
16478eb122450f127d66d4e8cf7f65cad80ea85d3acJeff Brown                draw(1.0f);
16578eb122450f127d66d4e8cf7f65cad80ea85d3acJeff Brown            }
16678eb122450f127d66d4e8cf7f65cad80ea85d3acJeff Brown        }
1679630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        return true;
1689630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    }
1699630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
1708b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown    private boolean tryPrepare() {
1718b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown        if (createSurface()) {
172252c206984299d7ce91c27536cafe1bb2fb9628dJeff Brown            if (mMode == MODE_FADE) {
1738b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown                return true;
1748b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown            }
1758b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown            return createEglContext()
1768b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown                    && createEglSurface()
1778b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown                    && captureScreenshotTextureAndSetViewport();
1788b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown        }
1798b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown        return false;
1808b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown    }
1818b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown
1829630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    /**
1839630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     * Dismisses the electron beam animation surface and cleans up.
1849630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     *
1859630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     * To prevent stray photons from leaking out after the electron beam has been
1869630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     * turned off, it is a good idea to defer dismissing the animation until the
1879630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     * electron beam has been turned back on fully.
1889630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     */
1899630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    public void dismiss() {
1909630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        if (DEBUG) {
1919630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            Slog.d(TAG, "dismiss");
1929630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        }
1939630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
1949630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        destroyScreenshotTexture();
1959630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        destroyEglSurface();
1968b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown        destroySurface();
1979630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        mPrepared = false;
1989630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    }
1999630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
2009630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    /**
2019630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     * Draws an animation frame showing the electron beam activated at the
2029630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     * specified level.
2039630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     *
2049630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     * @param level The electron beam level.
2059630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     * @return True if successful.
2069630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     */
2079630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    public boolean draw(float level) {
2089630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        if (DEBUG) {
2099630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            Slog.d(TAG, "drawFrame: level=" + level);
2109630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        }
2119630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
2128b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown        if (!mPrepared) {
2138b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown            return false;
2148b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown        }
2158b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown
216252c206984299d7ce91c27536cafe1bb2fb9628dJeff Brown        if (mMode == MODE_FADE) {
2178b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown            return showSurface(1.0f - level);
2188b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown        }
2198b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown
2209630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        if (!attachEglContext()) {
2219630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            return false;
2229630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        }
2239630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        try {
2249630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            // Clear frame to solid black.
2259630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            GLES10.glClearColor(0f, 0f, 0f, 1f);
2269630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            GLES10.glClear(GLES10.GL_COLOR_BUFFER_BIT);
2279630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
2289630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            // Draw the frame.
2299630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            if (level < HSTRETCH_DURATION) {
2309630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown                drawHStretch(1.0f - (level / HSTRETCH_DURATION));
2319630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            } else {
2329630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown                drawVStretch(1.0f - ((level - HSTRETCH_DURATION) / VSTRETCH_DURATION));
2339630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            }
2349630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            if (checkGlErrors("drawFrame")) {
2359630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown                return false;
2369630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            }
2379630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
2389630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            EGL14.eglSwapBuffers(mEglDisplay, mEglSurface);
2399630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        } finally {
2409630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            detachEglContext();
2419630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        }
2428b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown        return showSurface(1.0f);
2439630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    }
2449630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
2459630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    /**
2469630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     * Draws a frame where the content of the electron beam is collapsing inwards upon
2479630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     * itself vertically with red / green / blue channels dispersing and eventually
2489630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     * merging down to a single horizontal line.
2499630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     *
2509630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     * @param stretch The stretch factor.  0.0 is no collapse, 1.0 is full collapse.
2519630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     */
2529630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    private void drawVStretch(float stretch) {
2539630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        // compute interpolation scale factors for each color channel
2549630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        final float ar = scurve(stretch, 7.5f);
2559630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        final float ag = scurve(stretch, 8.0f);
2569630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        final float ab = scurve(stretch, 8.5f);
2579630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        if (DEBUG) {
2589630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            Slog.d(TAG, "drawVStretch: stretch=" + stretch
2599630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown                    + ", ar=" + ar + ", ag=" + ag + ", ab=" + ab);
2609630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        }
2619630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
2629630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        // set blending
2639630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        GLES10.glBlendFunc(GLES10.GL_ONE, GLES10.GL_ONE);
2649630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        GLES10.glEnable(GLES10.GL_BLEND);
2659630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
2669630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        // bind vertex buffer
2679630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        GLES10.glVertexPointer(2, GLES10.GL_FLOAT, 0, mVertexBuffer);
2689630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        GLES10.glEnableClientState(GLES10.GL_VERTEX_ARRAY);
2699630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
2700449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopian        // set-up texturing
2710449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopian        GLES10.glDisable(GLES10.GL_TEXTURE_2D);
2720449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopian        GLES10.glEnable(GLES11Ext.GL_TEXTURE_EXTERNAL_OES);
2730449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopian
2749630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        // bind texture and set blending for drawing planes
2750449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopian        GLES10.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTexNames[0]);
2769630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        GLES10.glTexEnvx(GLES10.GL_TEXTURE_ENV, GLES10.GL_TEXTURE_ENV_MODE,
2778b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown                mMode == MODE_WARM_UP ? GLES10.GL_MODULATE : GLES10.GL_REPLACE);
2780449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopian        GLES10.glTexParameterx(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
2799630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown                GLES10.GL_TEXTURE_MAG_FILTER, GLES10.GL_LINEAR);
2800449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopian        GLES10.glTexParameterx(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
2819630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown                GLES10.GL_TEXTURE_MIN_FILTER, GLES10.GL_LINEAR);
2820449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopian        GLES10.glTexParameterx(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
2839630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown                GLES10.GL_TEXTURE_WRAP_S, GLES10.GL_CLAMP_TO_EDGE);
2840449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopian        GLES10.glTexParameterx(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
2859630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown                GLES10.GL_TEXTURE_WRAP_T, GLES10.GL_CLAMP_TO_EDGE);
2860449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopian        GLES10.glEnable(GLES11Ext.GL_TEXTURE_EXTERNAL_OES);
2879630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        GLES10.glTexCoordPointer(2, GLES10.GL_FLOAT, 0, mTexCoordBuffer);
2889630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        GLES10.glEnableClientState(GLES10.GL_TEXTURE_COORD_ARRAY);
2899630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
2909630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        // draw the red plane
2919630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        setVStretchQuad(mVertexBuffer, mDisplayWidth, mDisplayHeight, ar);
2929630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        GLES10.glColorMask(true, false, false, true);
2939630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        GLES10.glDrawArrays(GLES10.GL_TRIANGLE_FAN, 0, 4);
2949630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
2959630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        // draw the green plane
2969630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        setVStretchQuad(mVertexBuffer, mDisplayWidth, mDisplayHeight, ag);
2979630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        GLES10.glColorMask(false, true, false, true);
2989630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        GLES10.glDrawArrays(GLES10.GL_TRIANGLE_FAN, 0, 4);
2999630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
3009630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        // draw the blue plane
3019630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        setVStretchQuad(mVertexBuffer, mDisplayWidth, mDisplayHeight, ab);
3029630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        GLES10.glColorMask(false, false, true, true);
3039630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        GLES10.glDrawArrays(GLES10.GL_TRIANGLE_FAN, 0, 4);
3049630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
3059630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        // clean up after drawing planes
3060449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopian        GLES10.glDisable(GLES11Ext.GL_TEXTURE_EXTERNAL_OES);
3079630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        GLES10.glDisableClientState(GLES10.GL_TEXTURE_COORD_ARRAY);
3089630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        GLES10.glColorMask(true, true, true, true);
3099630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
3109630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        // draw the white highlight (we use the last vertices)
3118b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown        if (mMode == MODE_COOL_DOWN) {
3129630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            GLES10.glColor4f(ag, ag, ag, 1.0f);
3139630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            GLES10.glDrawArrays(GLES10.GL_TRIANGLE_FAN, 0, 4);
3149630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        }
3159630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
3169630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        // clean up
3179630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        GLES10.glDisableClientState(GLES10.GL_VERTEX_ARRAY);
3189630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        GLES10.glDisable(GLES10.GL_BLEND);
3199630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    }
3209630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
3219630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    /**
3229630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     * Draws a frame where the electron beam has been stretched out into
32397f0aa6f8a8b7c1ed41786404423b9c9fcf789b8Mathias Agopian     * a thin white horizontal line that fades as it collapses inwards.
3249630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     *
32597f0aa6f8a8b7c1ed41786404423b9c9fcf789b8Mathias Agopian     * @param stretch The stretch factor.  0.0 is maximum stretch / no fade,
32697f0aa6f8a8b7c1ed41786404423b9c9fcf789b8Mathias Agopian     * 1.0 is collapsed / maximum fade.
3279630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     */
3289630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    private void drawHStretch(float stretch) {
3299630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        // compute interpolation scale factor
3309630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        final float ag = scurve(stretch, 8.0f);
3319630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        if (DEBUG) {
3329630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            Slog.d(TAG, "drawHStretch: stretch=" + stretch + ", ag=" + ag);
3339630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        }
3349630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
3359630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        if (stretch < 1.0f) {
3369630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            // bind vertex buffer
3379630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            GLES10.glVertexPointer(2, GLES10.GL_FLOAT, 0, mVertexBuffer);
3389630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            GLES10.glEnableClientState(GLES10.GL_VERTEX_ARRAY);
3399630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
3409630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            // draw narrow fading white line
3419630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            setHStretchQuad(mVertexBuffer, mDisplayWidth, mDisplayHeight, ag);
34297f0aa6f8a8b7c1ed41786404423b9c9fcf789b8Mathias Agopian            GLES10.glColor4f(1.0f - ag*0.75f, 1.0f - ag*0.75f, 1.0f - ag*0.75f, 1.0f);
3439630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            GLES10.glDrawArrays(GLES10.GL_TRIANGLE_FAN, 0, 4);
3449630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
3459630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            // clean up
3469630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            GLES10.glDisableClientState(GLES10.GL_VERTEX_ARRAY);
3479630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        }
3489630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    }
3499630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
3509630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    private static void setVStretchQuad(FloatBuffer vtx, float dw, float dh, float a) {
3519630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        final float w = dw + (dw * a);
3529630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        final float h = dh - (dh * a);
3539630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        final float x = (dw - w) * 0.5f;
3549630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        final float y = (dh - h) * 0.5f;
3559630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        setQuad(vtx, x, y, w, h);
3569630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    }
3579630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
3589630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    private static void setHStretchQuad(FloatBuffer vtx, float dw, float dh, float a) {
35997f0aa6f8a8b7c1ed41786404423b9c9fcf789b8Mathias Agopian        final float w = 2 * dw * (1.0f - a);
3609630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        final float h = 1.0f;
3619630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        final float x = (dw - w) * 0.5f;
3629630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        final float y = (dh - h) * 0.5f;
3639630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        setQuad(vtx, x, y, w, h);
3649630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    }
3659630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
3669630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    private static void setQuad(FloatBuffer vtx, float x, float y, float w, float h) {
3679630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        if (DEBUG) {
3689630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            Slog.d(TAG, "setQuad: x=" + x + ", y=" + y + ", w=" + w + ", h=" + h);
3699630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        }
3709630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        vtx.put(0, x);
3719630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        vtx.put(1, y);
3729630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        vtx.put(2, x);
3739630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        vtx.put(3, y + h);
3749630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        vtx.put(4, x + w);
3759630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        vtx.put(5, y + h);
3769630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        vtx.put(6, x + w);
3779630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        vtx.put(7, y);
3789630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    }
3799630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
3809630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    private boolean captureScreenshotTextureAndSetViewport() {
3810449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopian        if (!attachEglContext()) {
3829630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            return false;
3839630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        }
3849630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        try {
3850449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopian            if (!mTexNamesGenerated) {
3860449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopian                GLES10.glGenTextures(1, mTexNames, 0);
3870449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopian                if (checkGlErrors("glGenTextures")) {
3889630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown                    return false;
3899630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown                }
3900449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopian                mTexNamesGenerated = true;
3919630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            }
3920449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopian
39321ef9647e8bd9997ed63f891b13bc3cc0f566b52Jeff Sharkey            final SurfaceTexture st = new SurfaceTexture(mTexNames[0]);
39421ef9647e8bd9997ed63f891b13bc3cc0f566b52Jeff Sharkey            final Surface s = new Surface(st);
39521ef9647e8bd9997ed63f891b13bc3cc0f566b52Jeff Sharkey            try {
39621ef9647e8bd9997ed63f891b13bc3cc0f566b52Jeff Sharkey                SurfaceControl.screenshot(SurfaceControl.getBuiltInDisplay(
39721ef9647e8bd9997ed63f891b13bc3cc0f566b52Jeff Sharkey                        SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN), s);
39821ef9647e8bd9997ed63f891b13bc3cc0f566b52Jeff Sharkey            } finally {
39921ef9647e8bd9997ed63f891b13bc3cc0f566b52Jeff Sharkey                s.release();
40021ef9647e8bd9997ed63f891b13bc3cc0f566b52Jeff Sharkey            }
4010449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopian
4020449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopian            st.updateTexImage();
4030449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopian            st.getTransformMatrix(mTexMatrix);
4040449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopian
4050449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopian            // Set up texture coordinates for a quad.
4060449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopian            // We might need to change this if the texture ends up being
4070449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopian            // a different size from the display for some reason.
4080449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopian            mTexCoordBuffer.put(0, 0f); mTexCoordBuffer.put(1, 0f);
4090449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopian            mTexCoordBuffer.put(2, 0f); mTexCoordBuffer.put(3, 1f);
4100449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopian            mTexCoordBuffer.put(4, 1f); mTexCoordBuffer.put(5, 1f);
4110449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopian            mTexCoordBuffer.put(6, 1f); mTexCoordBuffer.put(7, 0f);
4120449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopian
4130449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopian            // Set up our viewport.
4140449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopian            GLES10.glViewport(0, 0, mDisplayWidth, mDisplayHeight);
4150449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopian            GLES10.glMatrixMode(GLES10.GL_PROJECTION);
4160449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopian            GLES10.glLoadIdentity();
4170449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopian            GLES10.glOrthof(0, mDisplayWidth, 0, mDisplayHeight, 0, 1);
4180449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopian            GLES10.glMatrixMode(GLES10.GL_MODELVIEW);
4190449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopian            GLES10.glLoadIdentity();
4200449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopian            GLES10.glMatrixMode(GLES10.GL_TEXTURE);
4210449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopian            GLES10.glLoadIdentity();
4220449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopian            GLES10.glLoadMatrixf(mTexMatrix, 0);
4239630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        } finally {
4240449a40586b45ee05f760802020dc2f8a6e0506bMathias Agopian            detachEglContext();
4259630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        }
4269630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        return true;
4279630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    }
4289630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
4299630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    private void destroyScreenshotTexture() {
4309630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        if (mTexNamesGenerated) {
4319630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            mTexNamesGenerated = false;
4329630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            if (attachEglContext()) {
4339630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown                try {
4349630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown                    GLES10.glDeleteTextures(1, mTexNames, 0);
4359630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown                    checkGlErrors("glDeleteTextures");
4369630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown                } finally {
4379630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown                    detachEglContext();
4389630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown                }
4399630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            }
4409630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        }
4419630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    }
4429630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
4439630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    private boolean createEglContext() {
4449630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        if (mEglDisplay == null) {
4459630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            mEglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
4469630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            if (mEglDisplay == EGL14.EGL_NO_DISPLAY) {
4479630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown                logEglError("eglGetDisplay");
4489630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown                return false;
4499630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            }
4509630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
4519630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            int[] version = new int[2];
4529630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            if (!EGL14.eglInitialize(mEglDisplay, version, 0, version, 1)) {
4539630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown                mEglDisplay = null;
4549630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown                logEglError("eglInitialize");
4559630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown                return false;
4569630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            }
4579630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        }
4589630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
4599630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        if (mEglConfig == null) {
4609630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            int[] eglConfigAttribList = new int[] {
4619630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown                    EGL14.EGL_RED_SIZE, 8,
4629630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown                    EGL14.EGL_GREEN_SIZE, 8,
4639630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown                    EGL14.EGL_BLUE_SIZE, 8,
4649630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown                    EGL14.EGL_ALPHA_SIZE, 8,
4659630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown                    EGL14.EGL_NONE
4669630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            };
4679630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            int[] numEglConfigs = new int[1];
4689630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            EGLConfig[] eglConfigs = new EGLConfig[1];
4699630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            if (!EGL14.eglChooseConfig(mEglDisplay, eglConfigAttribList, 0,
4709630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown                    eglConfigs, 0, eglConfigs.length, numEglConfigs, 0)) {
4719630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown                logEglError("eglChooseConfig");
4729630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown                return false;
4739630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            }
4749630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            mEglConfig = eglConfigs[0];
4759630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        }
4769630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
4779630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        if (mEglContext == null) {
4789630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            int[] eglContextAttribList = new int[] {
4799630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown                    EGL14.EGL_NONE
4809630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            };
4819630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            mEglContext = EGL14.eglCreateContext(mEglDisplay, mEglConfig,
4829630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown                    EGL14.EGL_NO_CONTEXT, eglContextAttribList, 0);
4839630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            if (mEglContext == null) {
4849630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown                logEglError("eglCreateContext");
4859630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown                return false;
4869630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            }
4879630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        }
4889630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        return true;
4899630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    }
4909630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
4919630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    /* not used because it is too expensive to create / destroy contexts all of the time
4929630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    private void destroyEglContext() {
4939630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        if (mEglContext != null) {
4949630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            if (!EGL14.eglDestroyContext(mEglDisplay, mEglContext)) {
4959630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown                logEglError("eglDestroyContext");
4969630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            }
4979630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            mEglContext = null;
4989630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        }
4999630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    }*/
5009630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
5018b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown    private boolean createSurface() {
5029630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        if (mSurfaceSession == null) {
5039630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            mSurfaceSession = new SurfaceSession();
5049630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        }
5059630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
5063866f0d581ceaa165710feeee9f37fe1b0d7067dMathias Agopian        SurfaceControl.openTransaction();
5079630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        try {
5083866f0d581ceaa165710feeee9f37fe1b0d7067dMathias Agopian            if (mSurfaceControl == null) {
5099630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown                try {
5108b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown                    int flags;
511252c206984299d7ce91c27536cafe1bb2fb9628dJeff Brown                    if (mMode == MODE_FADE) {
5123866f0d581ceaa165710feeee9f37fe1b0d7067dMathias Agopian                        flags = SurfaceControl.FX_SURFACE_DIM | SurfaceControl.HIDDEN;
5138b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown                    } else {
5143866f0d581ceaa165710feeee9f37fe1b0d7067dMathias Agopian                        flags = SurfaceControl.OPAQUE | SurfaceControl.HIDDEN;
5158b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown                    }
5163866f0d581ceaa165710feeee9f37fe1b0d7067dMathias Agopian                    mSurfaceControl = new SurfaceControl(mSurfaceSession,
51764a55af0ac700baecb0877235eb42caac59a3560Jeff Brown                            "ElectronBeam", mDisplayWidth, mDisplayHeight,
5188b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown                            PixelFormat.OPAQUE, flags);
519a86ab640f7bb0bf3cb4eaed80473ca8c5d131903Igor Murashkin                } catch (OutOfResourcesException ex) {
5209630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown                    Slog.e(TAG, "Unable to create surface.", ex);
5219630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown                    return false;
5229630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown                }
5239630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            }
5249630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
5253866f0d581ceaa165710feeee9f37fe1b0d7067dMathias Agopian            mSurfaceControl.setLayerStack(mDisplayLayerStack);
5263866f0d581ceaa165710feeee9f37fe1b0d7067dMathias Agopian            mSurfaceControl.setSize(mDisplayWidth, mDisplayHeight);
52786e1bc730570765355dc8789b5c6de6962a053ccMathias Agopian            mSurface = new Surface();
5283866f0d581ceaa165710feeee9f37fe1b0d7067dMathias Agopian            mSurface.copyFrom(mSurfaceControl);
529a86ab640f7bb0bf3cb4eaed80473ca8c5d131903Igor Murashkin
5303866f0d581ceaa165710feeee9f37fe1b0d7067dMathias Agopian            mSurfaceLayout = new NaturalSurfaceLayout(mDisplayManager, mSurfaceControl);
5317f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown            mSurfaceLayout.onDisplayTransaction();
5329630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        } finally {
5333866f0d581ceaa165710feeee9f37fe1b0d7067dMathias Agopian            SurfaceControl.closeTransaction();
5349630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        }
5358b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown        return true;
5368b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown    }
5379630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
5388b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown    private boolean createEglSurface() {
5399630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        if (mEglSurface == null) {
5409630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            int[] eglSurfaceAttribList = new int[] {
5419630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown                    EGL14.EGL_NONE
5429630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            };
5433866f0d581ceaa165710feeee9f37fe1b0d7067dMathias Agopian            // turn our SurfaceControl into a Surface
5449630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            mEglSurface = EGL14.eglCreateWindowSurface(mEglDisplay, mEglConfig, mSurface,
5459630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown                    eglSurfaceAttribList, 0);
5469630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            if (mEglSurface == null) {
5479630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown                logEglError("eglCreateWindowSurface");
5489630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown                return false;
5499630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            }
5509630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        }
5519630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        return true;
5529630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    }
5539630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
5549630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    private void destroyEglSurface() {
5559630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        if (mEglSurface != null) {
5569630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            if (!EGL14.eglDestroySurface(mEglDisplay, mEglSurface)) {
5579630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown                logEglError("eglDestroySurface");
5589630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            }
5599630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            mEglSurface = null;
5609630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        }
5618b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown    }
5629630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
5638b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown    private void destroySurface() {
5643866f0d581ceaa165710feeee9f37fe1b0d7067dMathias Agopian        if (mSurfaceControl != null) {
5657f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown            mSurfaceLayout.dispose();
5667f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown            mSurfaceLayout = null;
5673866f0d581ceaa165710feeee9f37fe1b0d7067dMathias Agopian            SurfaceControl.openTransaction();
5689630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            try {
5693866f0d581ceaa165710feeee9f37fe1b0d7067dMathias Agopian                mSurfaceControl.destroy();
5703866f0d581ceaa165710feeee9f37fe1b0d7067dMathias Agopian                mSurface.release();
5719630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            } finally {
5723866f0d581ceaa165710feeee9f37fe1b0d7067dMathias Agopian                SurfaceControl.closeTransaction();
5739630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            }
5743866f0d581ceaa165710feeee9f37fe1b0d7067dMathias Agopian            mSurfaceControl = null;
5759630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            mSurfaceVisible = false;
576252c206984299d7ce91c27536cafe1bb2fb9628dJeff Brown            mSurfaceAlpha = 0f;
5779630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        }
5789630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    }
5799630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
5808b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown    private boolean showSurface(float alpha) {
581252c206984299d7ce91c27536cafe1bb2fb9628dJeff Brown        if (!mSurfaceVisible || mSurfaceAlpha != alpha) {
5823866f0d581ceaa165710feeee9f37fe1b0d7067dMathias Agopian            SurfaceControl.openTransaction();
5839630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            try {
5843866f0d581ceaa165710feeee9f37fe1b0d7067dMathias Agopian                mSurfaceControl.setLayer(ELECTRON_BEAM_LAYER);
5853866f0d581ceaa165710feeee9f37fe1b0d7067dMathias Agopian                mSurfaceControl.setAlpha(alpha);
5863866f0d581ceaa165710feeee9f37fe1b0d7067dMathias Agopian                mSurfaceControl.show();
5879630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            } finally {
5883866f0d581ceaa165710feeee9f37fe1b0d7067dMathias Agopian                SurfaceControl.closeTransaction();
5899630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            }
5909630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            mSurfaceVisible = true;
591252c206984299d7ce91c27536cafe1bb2fb9628dJeff Brown            mSurfaceAlpha = alpha;
5929630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        }
5939630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        return true;
5949630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    }
5959630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
5969630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    private boolean attachEglContext() {
5979630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        if (mEglSurface == null) {
5989630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            return false;
5999630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        }
6009630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        if (!EGL14.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
6019630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            logEglError("eglMakeCurrent");
6029630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            return false;
6039630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        }
6049630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        return true;
6059630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    }
6069630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
6079630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    private void detachEglContext() {
6089630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        if (mEglDisplay != null) {
6099630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            EGL14.eglMakeCurrent(mEglDisplay,
6109630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown                    EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT);
6119630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        }
6129630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    }
6139630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
6149630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    /**
6159630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     * Interpolates a value in the range 0 .. 1 along a sigmoid curve
6169630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     * yielding a result in the range 0 .. 1 scaled such that:
6179630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     * scurve(0) == 0, scurve(0.5) == 0.5, scurve(1) == 1.
6189630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     */
6199630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    private static float scurve(float value, float s) {
6209630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        // A basic sigmoid has the form y = 1.0f / FloatMap.exp(-x * s).
6219630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        // Here we take the input datum and shift it by 0.5 so that the
6229630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        // domain spans the range -0.5 .. 0.5 instead of 0 .. 1.
6239630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        final float x = value - 0.5f;
6249630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
6259630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        // Next apply the sigmoid function to the scaled value
6269630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        // which produces a value in the range 0 .. 1 so we subtract
6279630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        // 0.5 to get a value in the range -0.5 .. 0.5 instead.
6289630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        final float y = sigmoid(x, s) - 0.5f;
6299630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
6309630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        // To obtain the desired boundary conditions we need to scale
6319630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        // the result so that it fills a range of -1 .. 1.
6329630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        final float v = sigmoid(0.5f, s) - 0.5f;
6339630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
6349630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        // And finally remap the value back to a range of 0 .. 1.
6359630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        return y / v * 0.5f + 0.5f;
6369630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    }
6379630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
6389630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    private static float sigmoid(float x, float s) {
6399630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        return 1.0f / (1.0f + FloatMath.exp(-x * s));
6409630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    }
6419630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
6429630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    private static FloatBuffer createNativeFloatBuffer(int size) {
6439630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        ByteBuffer bb = ByteBuffer.allocateDirect(size * 4);
6449630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        bb.order(ByteOrder.nativeOrder());
6459630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        return bb.asFloatBuffer();
6469630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    }
6479630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
6489630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    private static void logEglError(String func) {
6499630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        Slog.e(TAG, func + " failed: error " + EGL14.eglGetError(), new Throwable());
6509630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    }
6519630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
6529630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    private static boolean checkGlErrors(String func) {
6539630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        return checkGlErrors(func, true);
6549630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    }
6559630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
6569630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    private static boolean checkGlErrors(String func, boolean log) {
6579630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        boolean hadError = false;
6589630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        int error;
6599630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        while ((error = GLES10.glGetError()) != GLES10.GL_NO_ERROR) {
6609630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            if (log) {
6619630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown                Slog.e(TAG, func + " failed: error " + error, new Throwable());
6629630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            }
6639630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            hadError = true;
6649630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        }
6659630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        return hadError;
6669630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    }
6679630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
6689630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    public void dump(PrintWriter pw) {
6699630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        pw.println();
6709630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        pw.println("Electron Beam State:");
6719630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        pw.println("  mPrepared=" + mPrepared);
6728b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown        pw.println("  mMode=" + mMode);
6739630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        pw.println("  mDisplayLayerStack=" + mDisplayLayerStack);
6749630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        pw.println("  mDisplayWidth=" + mDisplayWidth);
6759630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        pw.println("  mDisplayHeight=" + mDisplayHeight);
6769630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        pw.println("  mSurfaceVisible=" + mSurfaceVisible);
677252c206984299d7ce91c27536cafe1bb2fb9628dJeff Brown        pw.println("  mSurfaceAlpha=" + mSurfaceAlpha);
6789630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    }
6797f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown
6807f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown    /**
6817f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown     * Keeps a surface aligned with the natural orientation of the device.
6827f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown     * Updates the position and transformation of the matrix whenever the display
6837f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown     * is rotated.  This is a little tricky because the display transaction
6847f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown     * callback can be invoked on any thread, not necessarily the thread that
6857f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown     * owns the electron beam.
6867f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown     */
6877f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown    private static final class NaturalSurfaceLayout implements DisplayTransactionListener {
6887f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown        private final DisplayManagerService mDisplayManager;
68929479ebe1007361222bf6ab4d5e2a27927d4b8e8Mathias Agopian        private SurfaceControl mSurfaceControl;
6907f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown
69129479ebe1007361222bf6ab4d5e2a27927d4b8e8Mathias Agopian        public NaturalSurfaceLayout(DisplayManagerService displayManager, SurfaceControl surfaceControl) {
6927f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown            mDisplayManager = displayManager;
69329479ebe1007361222bf6ab4d5e2a27927d4b8e8Mathias Agopian            mSurfaceControl = surfaceControl;
6947f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown            mDisplayManager.registerDisplayTransactionListener(this);
6957f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown        }
6967f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown
6977f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown        public void dispose() {
6987f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown            synchronized (this) {
69929479ebe1007361222bf6ab4d5e2a27927d4b8e8Mathias Agopian                mSurfaceControl = null;
7007f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown            }
7017f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown            mDisplayManager.unregisterDisplayTransactionListener(this);
7027f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown        }
7037f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown
7047f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown        @Override
7057f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown        public void onDisplayTransaction() {
7067f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown            synchronized (this) {
70729479ebe1007361222bf6ab4d5e2a27927d4b8e8Mathias Agopian                if (mSurfaceControl == null) {
7087f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown                    return;
7097f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown                }
7107f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown
7117f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown                DisplayInfo displayInfo = mDisplayManager.getDisplayInfo(Display.DEFAULT_DISPLAY);
7127f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown                switch (displayInfo.rotation) {
7137f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown                    case Surface.ROTATION_0:
71429479ebe1007361222bf6ab4d5e2a27927d4b8e8Mathias Agopian                        mSurfaceControl.setPosition(0, 0);
71529479ebe1007361222bf6ab4d5e2a27927d4b8e8Mathias Agopian                        mSurfaceControl.setMatrix(1, 0, 0, 1);
7167f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown                        break;
7177f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown                    case Surface.ROTATION_90:
71829479ebe1007361222bf6ab4d5e2a27927d4b8e8Mathias Agopian                        mSurfaceControl.setPosition(0, displayInfo.logicalHeight);
71929479ebe1007361222bf6ab4d5e2a27927d4b8e8Mathias Agopian                        mSurfaceControl.setMatrix(0, -1, 1, 0);
7207f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown                        break;
7217f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown                    case Surface.ROTATION_180:
72229479ebe1007361222bf6ab4d5e2a27927d4b8e8Mathias Agopian                        mSurfaceControl.setPosition(displayInfo.logicalWidth, displayInfo.logicalHeight);
72329479ebe1007361222bf6ab4d5e2a27927d4b8e8Mathias Agopian                        mSurfaceControl.setMatrix(-1, 0, 0, -1);
7247f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown                        break;
7257f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown                    case Surface.ROTATION_270:
72629479ebe1007361222bf6ab4d5e2a27927d4b8e8Mathias Agopian                        mSurfaceControl.setPosition(displayInfo.logicalWidth, 0);
72729479ebe1007361222bf6ab4d5e2a27927d4b8e8Mathias Agopian                        mSurfaceControl.setMatrix(0, 1, -1, 0);
7287f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown                        break;
7297f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown                }
7307f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown            }
7317f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown        }
7327f3994ec2a5dce1a037f04714b1f25cab85affb6Jeff Brown    }
7339630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown}
734