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