Home | History | Annotate | Download | only in display
      1 /*
      2  * Copyright (C) 2014 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.display;
     18 
     19 import java.io.IOException;
     20 import java.io.InputStream;
     21 import java.io.InputStreamReader;
     22 import java.io.PrintWriter;
     23 import java.nio.ByteBuffer;
     24 import java.nio.ByteOrder;
     25 import java.nio.FloatBuffer;
     26 
     27 import android.content.Context;
     28 import android.content.res.Resources;
     29 import android.graphics.PixelFormat;
     30 import android.graphics.SurfaceTexture;
     31 import android.hardware.display.DisplayManagerInternal;
     32 import android.hardware.display.DisplayManagerInternal.DisplayTransactionListener;
     33 import android.opengl.EGL14;
     34 import android.opengl.EGLConfig;
     35 import android.opengl.EGLContext;
     36 import android.opengl.EGLDisplay;
     37 import android.opengl.EGLSurface;
     38 import android.opengl.GLES20;
     39 import android.opengl.GLES11Ext;
     40 import android.util.FloatMath;
     41 import android.util.Slog;
     42 import android.view.DisplayInfo;
     43 import android.view.Surface.OutOfResourcesException;
     44 import android.view.Surface;
     45 import android.view.SurfaceControl;
     46 import android.view.SurfaceSession;
     47 
     48 import libcore.io.Streams;
     49 
     50 import com.android.server.LocalServices;
     51 import com.android.internal.R;
     52 
     53 /**
     54  * <p>
     55  * Animates a screen transition from on to off or off to on by applying
     56  * some GL transformations to a screenshot.
     57  * </p><p>
     58  * This component must only be created or accessed by the {@link Looper} thread
     59  * that belongs to the {@link DisplayPowerController}.
     60  * </p>
     61  */
     62 final class ColorFade {
     63     private static final String TAG = "ColorFade";
     64 
     65     private static final boolean DEBUG = false;
     66 
     67     // The layer for the electron beam surface.
     68     // This is currently hardcoded to be one layer above the boot animation.
     69     private static final int COLOR_FADE_LAYER = 0x40000001;
     70 
     71     // The number of frames to draw when preparing the animation so that it will
     72     // be ready to run smoothly.  We use 3 frames because we are triple-buffered.
     73     // See code for details.
     74     private static final int DEJANK_FRAMES = 3;
     75 
     76     private final int mDisplayId;
     77 
     78     // Set to true when the animation context has been fully prepared.
     79     private boolean mPrepared;
     80     private int mMode;
     81 
     82     private final DisplayManagerInternal mDisplayManagerInternal;
     83     private int mDisplayLayerStack; // layer stack associated with primary display
     84     private int mDisplayWidth;      // real width, not rotated
     85     private int mDisplayHeight;     // real height, not rotated
     86     private SurfaceSession mSurfaceSession;
     87     private SurfaceControl mSurfaceControl;
     88     private Surface mSurface;
     89     private NaturalSurfaceLayout mSurfaceLayout;
     90     private EGLDisplay mEglDisplay;
     91     private EGLConfig mEglConfig;
     92     private EGLContext mEglContext;
     93     private EGLSurface mEglSurface;
     94     private boolean mSurfaceVisible;
     95     private float mSurfaceAlpha;
     96 
     97     // Texture names.  We only use one texture, which contains the screenshot.
     98     private final int[] mTexNames = new int[1];
     99     private boolean mTexNamesGenerated;
    100     private final float mTexMatrix[] = new float[16];
    101     private final float mProjMatrix[] = new float[16];
    102     private final int[] mGLBuffers = new int[2];
    103     private int mTexCoordLoc, mVertexLoc, mTexUnitLoc, mProjMatrixLoc, mTexMatrixLoc;
    104     private int mOpacityLoc, mScaleLoc, mGammaLoc, mSaturationLoc;
    105     private int mProgram;
    106 
    107     // Vertex and corresponding texture coordinates.
    108     // We have 4 2D vertices, so 8 elements.  The vertices form a quad.
    109     private final FloatBuffer mVertexBuffer = createNativeFloatBuffer(8);
    110     private final FloatBuffer mTexCoordBuffer = createNativeFloatBuffer(8);
    111 
    112     /**
    113      * Animates an color fade warming up.
    114      */
    115     public static final int MODE_WARM_UP = 0;
    116 
    117     /**
    118      * Animates an color fade shutting off.
    119      */
    120     public static final int MODE_COOL_DOWN = 1;
    121 
    122     /**
    123      * Animates a simple dim layer to fade the contents of the screen in or out progressively.
    124      */
    125     public static final int MODE_FADE = 2;
    126 
    127     public ColorFade(int displayId) {
    128         mDisplayId = displayId;
    129         mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
    130     }
    131 
    132     /**
    133      * Warms up the color fade in preparation for turning on or off.
    134      * This method prepares a GL context, and captures a screen shot.
    135      *
    136      * @param mode The desired mode for the upcoming animation.
    137      * @return True if the color fade is ready, false if it is uncontrollable.
    138      */
    139     public boolean prepare(Context context, int mode) {
    140         if (DEBUG) {
    141             Slog.d(TAG, "prepare: mode=" + mode);
    142         }
    143 
    144         mMode = mode;
    145 
    146         // Get the display size and layer stack.
    147         // This is not expected to change while the color fade surface is showing.
    148         DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId);
    149         mDisplayLayerStack = displayInfo.layerStack;
    150         mDisplayWidth = displayInfo.getNaturalWidth();
    151         mDisplayHeight = displayInfo.getNaturalHeight();
    152 
    153         // Prepare the surface for drawing.
    154         if (!(createSurface() && createEglContext() && createEglSurface() &&
    155               captureScreenshotTextureAndSetViewport())) {
    156             dismiss();
    157             return false;
    158         }
    159 
    160         // Init GL
    161         if (!attachEglContext()) {
    162             return false;
    163         }
    164         try {
    165             if(!initGLShaders(context) || !initGLBuffers() || checkGlErrors("prepare")) {
    166                 detachEglContext();
    167                 dismiss();
    168                 return false;
    169             }
    170         } finally {
    171             detachEglContext();
    172         }
    173 
    174         // Done.
    175         mPrepared = true;
    176 
    177         // Dejanking optimization.
    178         // Some GL drivers can introduce a lot of lag in the first few frames as they
    179         // initialize their state and allocate graphics buffers for rendering.
    180         // Work around this problem by rendering the first frame of the animation a few
    181         // times.  The rest of the animation should run smoothly thereafter.
    182         // The frames we draw here aren't visible because we are essentially just
    183         // painting the screenshot as-is.
    184         if (mode == MODE_COOL_DOWN) {
    185             for (int i = 0; i < DEJANK_FRAMES; i++) {
    186                 draw(1.0f);
    187             }
    188         }
    189         return true;
    190     }
    191 
    192     private String readFile(Context context, int resourceId) {
    193         try{
    194             InputStream stream = context.getResources().openRawResource(resourceId);
    195             return new String(Streams.readFully(new InputStreamReader(stream)));
    196         }
    197         catch (IOException e) {
    198             Slog.e(TAG, "Unrecognized shader " + Integer.toString(resourceId));
    199             throw new RuntimeException(e);
    200         }
    201     }
    202 
    203     private int loadShader(Context context, int resourceId, int type) {
    204         String source = readFile(context, resourceId);
    205 
    206         int shader = GLES20.glCreateShader(type);
    207 
    208         GLES20.glShaderSource(shader, source);
    209         GLES20.glCompileShader(shader);
    210 
    211         int[] compiled = new int[1];
    212         GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
    213         if (compiled[0] == 0) {
    214             Slog.e(TAG, "Could not compile shader " + shader + ", " + type + ":");
    215             Slog.e(TAG, GLES20.glGetShaderSource(shader));
    216             Slog.e(TAG, GLES20.glGetShaderInfoLog(shader));
    217             GLES20.glDeleteShader(shader);
    218             shader = 0;
    219         }
    220 
    221         return shader;
    222     }
    223 
    224     private boolean initGLShaders(Context context) {
    225         int vshader = loadShader(context, com.android.internal.R.raw.color_fade_vert,
    226                 GLES20.GL_VERTEX_SHADER);
    227         int fshader = loadShader(context, com.android.internal.R.raw.color_fade_frag,
    228                 GLES20.GL_FRAGMENT_SHADER);
    229         GLES20.glReleaseShaderCompiler();
    230         if (vshader == 0 || fshader == 0) return false;
    231 
    232         mProgram = GLES20.glCreateProgram();
    233 
    234         GLES20.glAttachShader(mProgram, vshader);
    235         GLES20.glAttachShader(mProgram, fshader);
    236         GLES20.glDeleteShader(vshader);
    237         GLES20.glDeleteShader(fshader);
    238 
    239         GLES20.glLinkProgram(mProgram);
    240 
    241         mVertexLoc = GLES20.glGetAttribLocation(mProgram, "position");
    242         mTexCoordLoc = GLES20.glGetAttribLocation(mProgram, "uv");
    243 
    244         mProjMatrixLoc = GLES20.glGetUniformLocation(mProgram, "proj_matrix");
    245         mTexMatrixLoc = GLES20.glGetUniformLocation(mProgram, "tex_matrix");
    246 
    247         mOpacityLoc = GLES20.glGetUniformLocation(mProgram, "opacity");
    248         mGammaLoc = GLES20.glGetUniformLocation(mProgram, "gamma");
    249         mSaturationLoc = GLES20.glGetUniformLocation(mProgram, "saturation");
    250         mScaleLoc = GLES20.glGetUniformLocation(mProgram, "scale");
    251         mTexUnitLoc = GLES20.glGetUniformLocation(mProgram, "texUnit");
    252 
    253         GLES20.glUseProgram(mProgram);
    254         GLES20.glUniform1i(mTexUnitLoc, 0);
    255         GLES20.glUseProgram(0);
    256 
    257         return true;
    258     }
    259 
    260     private void destroyGLShaders() {
    261         GLES20.glDeleteProgram(mProgram);
    262         checkGlErrors("glDeleteProgram");
    263     }
    264 
    265     private boolean initGLBuffers() {
    266         //Fill vertices
    267         setQuad(mVertexBuffer, 0, 0, mDisplayWidth, mDisplayHeight);
    268 
    269         // Setup GL Textures
    270         GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTexNames[0]);
    271         GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER,
    272                 GLES20.GL_NEAREST);
    273         GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER,
    274                 GLES20.GL_NEAREST);
    275         GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S,
    276                 GLES20.GL_CLAMP_TO_EDGE);
    277         GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T,
    278                 GLES20.GL_CLAMP_TO_EDGE);
    279         GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0);
    280 
    281         // Setup GL Buffers
    282         GLES20.glGenBuffers(2, mGLBuffers, 0);
    283 
    284         // fill vertex buffer
    285         GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLBuffers[0]);
    286         GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, mVertexBuffer.capacity() * 4,
    287                             mVertexBuffer, GLES20.GL_STATIC_DRAW);
    288 
    289         // fill tex buffer
    290         GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLBuffers[1]);
    291         GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, mTexCoordBuffer.capacity() * 4,
    292                             mTexCoordBuffer, GLES20.GL_STATIC_DRAW);
    293 
    294         GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
    295 
    296         return true;
    297     }
    298 
    299     private void destroyGLBuffers() {
    300         GLES20.glDeleteBuffers(2, mGLBuffers, 0);
    301         checkGlErrors("glDeleteBuffers");
    302     }
    303 
    304     private static void setQuad(FloatBuffer vtx, float x, float y, float w, float h) {
    305         if (DEBUG) {
    306             Slog.d(TAG, "setQuad: x=" + x + ", y=" + y + ", w=" + w + ", h=" + h);
    307         }
    308         vtx.put(0, x);
    309         vtx.put(1, y);
    310         vtx.put(2, x);
    311         vtx.put(3, y + h);
    312         vtx.put(4, x + w);
    313         vtx.put(5, y + h);
    314         vtx.put(6, x + w);
    315         vtx.put(7, y);
    316     }
    317 
    318     /**
    319      * Dismisses the color fade animation surface and cleans up.
    320      *
    321      * To prevent stray photons from leaking out after the color fade has been
    322      * turned off, it is a good idea to defer dismissing the animation until the
    323      * color fade has been turned back on fully.
    324      */
    325     public void dismiss() {
    326         if (DEBUG) {
    327             Slog.d(TAG, "dismiss");
    328         }
    329 
    330         if (mPrepared) {
    331             attachEglContext();
    332             try {
    333                 destroyScreenshotTexture();
    334                 destroyGLShaders();
    335                 destroyGLBuffers();
    336                 destroyEglSurface();
    337             } finally {
    338                 detachEglContext();
    339             }
    340             destroySurface();
    341             GLES20.glFlush();
    342             mPrepared = false;
    343         }
    344     }
    345 
    346     /**
    347      * Draws an animation frame showing the color fade activated at the
    348      * specified level.
    349      *
    350      * @param level The color fade level.
    351      * @return True if successful.
    352      */
    353     public boolean draw(float level) {
    354         if (DEBUG) {
    355             Slog.d(TAG, "drawFrame: level=" + level);
    356         }
    357 
    358         if (!mPrepared) {
    359             return false;
    360         }
    361 
    362         if (mMode == MODE_FADE) {
    363             return showSurface(1.0f - level);
    364         }
    365 
    366         if (!attachEglContext()) {
    367             return false;
    368         }
    369         try {
    370             // Clear frame to solid black.
    371             GLES20.glClearColor(0f, 0f, 0f, 1f);
    372             GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
    373 
    374             // Draw the frame.
    375             float one_minus_level = 1 - level;
    376             float cos = FloatMath.cos((float)Math.PI * one_minus_level);
    377             float sign = cos < 0 ? -1 : 1;
    378             float opacity = -FloatMath.pow(one_minus_level, 2) + 1;
    379             float saturation = FloatMath.pow(level, 4);
    380             float scale = (-FloatMath.pow(one_minus_level, 2) + 1) * 0.1f + 0.9f;
    381             float gamma = (0.5f * sign * FloatMath.pow(cos, 2) + 0.5f) * 0.9f + 0.1f;
    382             drawFaded(opacity, 1.f / gamma, saturation, scale);
    383             if (checkGlErrors("drawFrame")) {
    384                 return false;
    385             }
    386 
    387             EGL14.eglSwapBuffers(mEglDisplay, mEglSurface);
    388         } finally {
    389             detachEglContext();
    390         }
    391         return showSurface(1.0f);
    392     }
    393 
    394     private void drawFaded(float opacity, float gamma, float saturation, float scale) {
    395         if (DEBUG) {
    396             Slog.d(TAG, "drawFaded: opacity=" + opacity + ", gamma=" + gamma +
    397                         ", saturation=" + saturation + ", scale=" + scale);
    398         }
    399         // Use shaders
    400         GLES20.glUseProgram(mProgram);
    401 
    402         // Set Uniforms
    403         GLES20.glUniformMatrix4fv(mProjMatrixLoc, 1, false, mProjMatrix, 0);
    404         GLES20.glUniformMatrix4fv(mTexMatrixLoc, 1, false, mTexMatrix, 0);
    405         GLES20.glUniform1f(mOpacityLoc, opacity);
    406         GLES20.glUniform1f(mGammaLoc, gamma);
    407         GLES20.glUniform1f(mSaturationLoc, saturation);
    408         GLES20.glUniform1f(mScaleLoc, scale);
    409 
    410         // Use textures
    411         GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
    412         GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTexNames[0]);
    413 
    414         // draw the plane
    415         GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLBuffers[0]);
    416         GLES20.glEnableVertexAttribArray(mVertexLoc);
    417         GLES20.glVertexAttribPointer(mVertexLoc, 2, GLES20.GL_FLOAT, false, 0, 0);
    418 
    419         GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLBuffers[1]);
    420         GLES20.glEnableVertexAttribArray(mTexCoordLoc);
    421         GLES20.glVertexAttribPointer(mTexCoordLoc, 2, GLES20.GL_FLOAT, false, 0, 0);
    422 
    423         GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 4);
    424 
    425         // clean up
    426         GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0);
    427         GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
    428     }
    429 
    430     private void ortho(float left, float right, float bottom, float top, float znear, float zfar) {
    431         mProjMatrix[0] = 2f / (right - left);
    432         mProjMatrix[1] = 0;
    433         mProjMatrix[2] = 0;
    434         mProjMatrix[3] = 0;
    435         mProjMatrix[4] = 0;
    436         mProjMatrix[5] = 2f / (top - bottom);
    437         mProjMatrix[6] = 0;
    438         mProjMatrix[7] = 0;
    439         mProjMatrix[8] = 0;
    440         mProjMatrix[9] = 0;
    441         mProjMatrix[10] = -2f / (zfar - znear);
    442         mProjMatrix[11] = 0;
    443         mProjMatrix[12] = -(right + left) / (right - left);
    444         mProjMatrix[13] = -(top + bottom) / (top - bottom);
    445         mProjMatrix[14] = -(zfar + znear) / (zfar - znear);
    446         mProjMatrix[15] = 1f;
    447     }
    448 
    449     private boolean captureScreenshotTextureAndSetViewport() {
    450         if (!attachEglContext()) {
    451             return false;
    452         }
    453         try {
    454             if (!mTexNamesGenerated) {
    455                 GLES20.glGenTextures(1, mTexNames, 0);
    456                 if (checkGlErrors("glGenTextures")) {
    457                     return false;
    458                 }
    459                 mTexNamesGenerated = true;
    460             }
    461 
    462             final SurfaceTexture st = new SurfaceTexture(mTexNames[0]);
    463             final Surface s = new Surface(st);
    464             try {
    465                 SurfaceControl.screenshot(SurfaceControl.getBuiltInDisplay(
    466                         SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN), s);
    467             } finally {
    468                 s.release();
    469             }
    470 
    471             st.updateTexImage();
    472             st.getTransformMatrix(mTexMatrix);
    473 
    474             // Set up texture coordinates for a quad.
    475             // We might need to change this if the texture ends up being
    476             // a different size from the display for some reason.
    477             mTexCoordBuffer.put(0, 0f); mTexCoordBuffer.put(1, 0f);
    478             mTexCoordBuffer.put(2, 0f); mTexCoordBuffer.put(3, 1f);
    479             mTexCoordBuffer.put(4, 1f); mTexCoordBuffer.put(5, 1f);
    480             mTexCoordBuffer.put(6, 1f); mTexCoordBuffer.put(7, 0f);
    481 
    482             // Set up our viewport.
    483             GLES20.glViewport(0, 0, mDisplayWidth, mDisplayHeight);
    484             ortho(0, mDisplayWidth, 0, mDisplayHeight, -1, 1);
    485         } finally {
    486             detachEglContext();
    487         }
    488         return true;
    489     }
    490 
    491     private void destroyScreenshotTexture() {
    492         if (mTexNamesGenerated) {
    493             mTexNamesGenerated = false;
    494             GLES20.glDeleteTextures(1, mTexNames, 0);
    495             checkGlErrors("glDeleteTextures");
    496         }
    497     }
    498 
    499     private boolean createEglContext() {
    500         if (mEglDisplay == null) {
    501             mEglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
    502             if (mEglDisplay == EGL14.EGL_NO_DISPLAY) {
    503                 logEglError("eglGetDisplay");
    504                 return false;
    505             }
    506 
    507             int[] version = new int[2];
    508             if (!EGL14.eglInitialize(mEglDisplay, version, 0, version, 1)) {
    509                 mEglDisplay = null;
    510                 logEglError("eglInitialize");
    511                 return false;
    512             }
    513         }
    514 
    515         if (mEglConfig == null) {
    516             int[] eglConfigAttribList = new int[] {
    517                     EGL14.EGL_RENDERABLE_TYPE,
    518                     EGL14.EGL_OPENGL_ES2_BIT,
    519                     EGL14.EGL_RED_SIZE, 8,
    520                     EGL14.EGL_GREEN_SIZE, 8,
    521                     EGL14.EGL_BLUE_SIZE, 8,
    522                     EGL14.EGL_ALPHA_SIZE, 8,
    523                     EGL14.EGL_NONE
    524             };
    525             int[] numEglConfigs = new int[1];
    526             EGLConfig[] eglConfigs = new EGLConfig[1];
    527             if (!EGL14.eglChooseConfig(mEglDisplay, eglConfigAttribList, 0,
    528                     eglConfigs, 0, eglConfigs.length, numEglConfigs, 0)) {
    529                 logEglError("eglChooseConfig");
    530                 return false;
    531             }
    532             mEglConfig = eglConfigs[0];
    533         }
    534 
    535         if (mEglContext == null) {
    536             int[] eglContextAttribList = new int[] {
    537                     EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,
    538                     EGL14.EGL_NONE
    539             };
    540             mEglContext = EGL14.eglCreateContext(mEglDisplay, mEglConfig,
    541                     EGL14.EGL_NO_CONTEXT, eglContextAttribList, 0);
    542             if (mEglContext == null) {
    543                 logEglError("eglCreateContext");
    544                 return false;
    545             }
    546         }
    547         return true;
    548     }
    549 
    550     private boolean createSurface() {
    551         if (mSurfaceSession == null) {
    552             mSurfaceSession = new SurfaceSession();
    553         }
    554 
    555         SurfaceControl.openTransaction();
    556         try {
    557             if (mSurfaceControl == null) {
    558                 try {
    559                     int flags;
    560                     if (mMode == MODE_FADE) {
    561                         flags = SurfaceControl.FX_SURFACE_DIM | SurfaceControl.HIDDEN;
    562                     } else {
    563                         flags = SurfaceControl.OPAQUE | SurfaceControl.HIDDEN;
    564                     }
    565                     mSurfaceControl = new SurfaceControl(mSurfaceSession,
    566                             "ColorFade", mDisplayWidth, mDisplayHeight,
    567                             PixelFormat.OPAQUE, flags);
    568                 } catch (OutOfResourcesException ex) {
    569                     Slog.e(TAG, "Unable to create surface.", ex);
    570                     return false;
    571                 }
    572             }
    573 
    574             mSurfaceControl.setLayerStack(mDisplayLayerStack);
    575             mSurfaceControl.setSize(mDisplayWidth, mDisplayHeight);
    576             mSurface = new Surface();
    577             mSurface.copyFrom(mSurfaceControl);
    578 
    579             mSurfaceLayout = new NaturalSurfaceLayout(mDisplayManagerInternal,
    580                     mDisplayId, mSurfaceControl);
    581             mSurfaceLayout.onDisplayTransaction();
    582         } finally {
    583             SurfaceControl.closeTransaction();
    584         }
    585         return true;
    586     }
    587 
    588     private boolean createEglSurface() {
    589         if (mEglSurface == null) {
    590             int[] eglSurfaceAttribList = new int[] {
    591                     EGL14.EGL_NONE
    592             };
    593             // turn our SurfaceControl into a Surface
    594             mEglSurface = EGL14.eglCreateWindowSurface(mEglDisplay, mEglConfig, mSurface,
    595                     eglSurfaceAttribList, 0);
    596             if (mEglSurface == null) {
    597                 logEglError("eglCreateWindowSurface");
    598                 return false;
    599             }
    600         }
    601         return true;
    602     }
    603 
    604     private void destroyEglSurface() {
    605         if (mEglSurface != null) {
    606             if (!EGL14.eglDestroySurface(mEglDisplay, mEglSurface)) {
    607                 logEglError("eglDestroySurface");
    608             }
    609             mEglSurface = null;
    610         }
    611     }
    612 
    613     private void destroySurface() {
    614         if (mSurfaceControl != null) {
    615             mSurfaceLayout.dispose();
    616             mSurfaceLayout = null;
    617             SurfaceControl.openTransaction();
    618             try {
    619                 mSurfaceControl.destroy();
    620                 mSurface.release();
    621             } finally {
    622                 SurfaceControl.closeTransaction();
    623             }
    624             mSurfaceControl = null;
    625             mSurfaceVisible = false;
    626             mSurfaceAlpha = 0f;
    627         }
    628     }
    629 
    630     private boolean showSurface(float alpha) {
    631         if (!mSurfaceVisible || mSurfaceAlpha != alpha) {
    632             SurfaceControl.openTransaction();
    633             try {
    634                 mSurfaceControl.setLayer(COLOR_FADE_LAYER);
    635                 mSurfaceControl.setAlpha(alpha);
    636                 mSurfaceControl.show();
    637             } finally {
    638                 SurfaceControl.closeTransaction();
    639             }
    640             mSurfaceVisible = true;
    641             mSurfaceAlpha = alpha;
    642         }
    643         return true;
    644     }
    645 
    646     private boolean attachEglContext() {
    647         if (mEglSurface == null) {
    648             return false;
    649         }
    650         if (!EGL14.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
    651             logEglError("eglMakeCurrent");
    652             return false;
    653         }
    654         return true;
    655     }
    656 
    657     private void detachEglContext() {
    658         if (mEglDisplay != null) {
    659             EGL14.eglMakeCurrent(mEglDisplay,
    660                     EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT);
    661         }
    662     }
    663 
    664     private static FloatBuffer createNativeFloatBuffer(int size) {
    665         ByteBuffer bb = ByteBuffer.allocateDirect(size * 4);
    666         bb.order(ByteOrder.nativeOrder());
    667         return bb.asFloatBuffer();
    668     }
    669 
    670     private static void logEglError(String func) {
    671         Slog.e(TAG, func + " failed: error " + EGL14.eglGetError(), new Throwable());
    672     }
    673 
    674     private static boolean checkGlErrors(String func) {
    675         return checkGlErrors(func, true);
    676     }
    677 
    678     private static boolean checkGlErrors(String func, boolean log) {
    679         boolean hadError = false;
    680         int error;
    681         while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
    682             if (log) {
    683                 Slog.e(TAG, func + " failed: error " + error, new Throwable());
    684             }
    685             hadError = true;
    686         }
    687         return hadError;
    688     }
    689 
    690     public void dump(PrintWriter pw) {
    691         pw.println();
    692         pw.println("Color Fade State:");
    693         pw.println("  mPrepared=" + mPrepared);
    694         pw.println("  mMode=" + mMode);
    695         pw.println("  mDisplayLayerStack=" + mDisplayLayerStack);
    696         pw.println("  mDisplayWidth=" + mDisplayWidth);
    697         pw.println("  mDisplayHeight=" + mDisplayHeight);
    698         pw.println("  mSurfaceVisible=" + mSurfaceVisible);
    699         pw.println("  mSurfaceAlpha=" + mSurfaceAlpha);
    700     }
    701 
    702     /**
    703      * Keeps a surface aligned with the natural orientation of the device.
    704      * Updates the position and transformation of the matrix whenever the display
    705      * is rotated.  This is a little tricky because the display transaction
    706      * callback can be invoked on any thread, not necessarily the thread that
    707      * owns the color fade.
    708      */
    709     private static final class NaturalSurfaceLayout implements DisplayTransactionListener {
    710         private final DisplayManagerInternal mDisplayManagerInternal;
    711         private final int mDisplayId;
    712         private SurfaceControl mSurfaceControl;
    713 
    714         public NaturalSurfaceLayout(DisplayManagerInternal displayManagerInternal,
    715                 int displayId, SurfaceControl surfaceControl) {
    716             mDisplayManagerInternal = displayManagerInternal;
    717             mDisplayId = displayId;
    718             mSurfaceControl = surfaceControl;
    719             mDisplayManagerInternal.registerDisplayTransactionListener(this);
    720         }
    721 
    722         public void dispose() {
    723             synchronized (this) {
    724                 mSurfaceControl = null;
    725             }
    726             mDisplayManagerInternal.unregisterDisplayTransactionListener(this);
    727         }
    728 
    729         @Override
    730         public void onDisplayTransaction() {
    731             synchronized (this) {
    732                 if (mSurfaceControl == null) {
    733                     return;
    734                 }
    735 
    736                 DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId);
    737                 switch (displayInfo.rotation) {
    738                     case Surface.ROTATION_0:
    739                         mSurfaceControl.setPosition(0, 0);
    740                         mSurfaceControl.setMatrix(1, 0, 0, 1);
    741                         break;
    742                     case Surface.ROTATION_90:
    743                         mSurfaceControl.setPosition(0, displayInfo.logicalHeight);
    744                         mSurfaceControl.setMatrix(0, -1, 1, 0);
    745                         break;
    746                     case Surface.ROTATION_180:
    747                         mSurfaceControl.setPosition(displayInfo.logicalWidth,
    748                                 displayInfo.logicalHeight);
    749                         mSurfaceControl.setMatrix(-1, 0, 0, -1);
    750                         break;
    751                     case Surface.ROTATION_270:
    752                         mSurfaceControl.setPosition(displayInfo.logicalWidth, 0);
    753                         mSurfaceControl.setMatrix(0, 1, -1, 0);
    754                         break;
    755                 }
    756             }
    757         }
    758     }
    759 }
    760