Home | History | Annotate | Download | only in glwallpaper
      1 /*
      2  * Copyright (C) 2019 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.systemui.glwallpaper;
     18 
     19 import static android.opengl.EGL14.EGL_ALPHA_SIZE;
     20 import static android.opengl.EGL14.EGL_BLUE_SIZE;
     21 import static android.opengl.EGL14.EGL_CONFIG_CAVEAT;
     22 import static android.opengl.EGL14.EGL_CONTEXT_CLIENT_VERSION;
     23 import static android.opengl.EGL14.EGL_DEFAULT_DISPLAY;
     24 import static android.opengl.EGL14.EGL_DEPTH_SIZE;
     25 import static android.opengl.EGL14.EGL_GREEN_SIZE;
     26 import static android.opengl.EGL14.EGL_NONE;
     27 import static android.opengl.EGL14.EGL_NO_CONTEXT;
     28 import static android.opengl.EGL14.EGL_NO_DISPLAY;
     29 import static android.opengl.EGL14.EGL_NO_SURFACE;
     30 import static android.opengl.EGL14.EGL_OPENGL_ES2_BIT;
     31 import static android.opengl.EGL14.EGL_RED_SIZE;
     32 import static android.opengl.EGL14.EGL_RENDERABLE_TYPE;
     33 import static android.opengl.EGL14.EGL_STENCIL_SIZE;
     34 import static android.opengl.EGL14.EGL_SUCCESS;
     35 import static android.opengl.EGL14.eglChooseConfig;
     36 import static android.opengl.EGL14.eglCreateContext;
     37 import static android.opengl.EGL14.eglCreateWindowSurface;
     38 import static android.opengl.EGL14.eglDestroyContext;
     39 import static android.opengl.EGL14.eglDestroySurface;
     40 import static android.opengl.EGL14.eglGetDisplay;
     41 import static android.opengl.EGL14.eglGetError;
     42 import static android.opengl.EGL14.eglInitialize;
     43 import static android.opengl.EGL14.eglMakeCurrent;
     44 import static android.opengl.EGL14.eglSwapBuffers;
     45 import static android.opengl.EGL14.eglTerminate;
     46 
     47 import android.opengl.EGLConfig;
     48 import android.opengl.EGLContext;
     49 import android.opengl.EGLDisplay;
     50 import android.opengl.EGLSurface;
     51 import android.opengl.GLUtils;
     52 import android.util.Log;
     53 import android.view.SurfaceHolder;
     54 
     55 import java.io.FileDescriptor;
     56 import java.io.PrintWriter;
     57 
     58 /**
     59  * A helper class to handle EGL management.
     60  */
     61 public class EglHelper {
     62     private static final String TAG = EglHelper.class.getSimpleName();
     63     // Below two constants make drawing at low priority, so other things can preempt our drawing.
     64     private static final int EGL_CONTEXT_PRIORITY_LEVEL_IMG = 0x3100;
     65     private static final int EGL_CONTEXT_PRIORITY_LOW_IMG = 0x3103;
     66 
     67     private EGLDisplay mEglDisplay;
     68     private EGLConfig mEglConfig;
     69     private EGLContext mEglContext;
     70     private EGLSurface mEglSurface;
     71     private final int[] mEglVersion = new int[2];
     72     private boolean mEglReady;
     73 
     74     /**
     75      * Initialize EGL and prepare EglSurface.
     76      * @param surfaceHolder surface holder.
     77      * @return true if EglSurface is ready.
     78      */
     79     public boolean init(SurfaceHolder surfaceHolder) {
     80         mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
     81         if (mEglDisplay == EGL_NO_DISPLAY) {
     82             Log.w(TAG, "eglGetDisplay failed: " + GLUtils.getEGLErrorString(eglGetError()));
     83             return false;
     84         }
     85 
     86         if (!eglInitialize(mEglDisplay, mEglVersion, 0 /* majorOffset */,
     87                     mEglVersion, 1 /* minorOffset */)) {
     88             Log.w(TAG, "eglInitialize failed: " + GLUtils.getEGLErrorString(eglGetError()));
     89             return false;
     90         }
     91 
     92         mEglConfig = chooseEglConfig();
     93         if (mEglConfig == null) {
     94             Log.w(TAG, "eglConfig not initialized!");
     95             return false;
     96         }
     97 
     98         if (!createEglContext()) {
     99             Log.w(TAG, "Can't create EGLContext!");
    100             return false;
    101         }
    102 
    103         if (!createEglSurface(surfaceHolder)) {
    104             Log.w(TAG, "Can't create EGLSurface!");
    105             return false;
    106         }
    107 
    108         mEglReady = true;
    109         return true;
    110     }
    111 
    112     private EGLConfig chooseEglConfig() {
    113         int[] configsCount = new int[1];
    114         EGLConfig[] configs = new EGLConfig[1];
    115         int[] configSpec = getConfig();
    116         if (!eglChooseConfig(mEglDisplay, configSpec, 0, configs, 0, 1, configsCount, 0)) {
    117             Log.w(TAG, "eglChooseConfig failed: " + GLUtils.getEGLErrorString(eglGetError()));
    118             return null;
    119         } else {
    120             if (configsCount[0] <= 0) {
    121                 Log.w(TAG, "eglChooseConfig failed, invalid configs count: " + configsCount[0]);
    122                 return null;
    123             } else {
    124                 return configs[0];
    125             }
    126         }
    127     }
    128 
    129     private int[] getConfig() {
    130         return new int[] {
    131             EGL_RED_SIZE, 8,
    132             EGL_GREEN_SIZE, 8,
    133             EGL_BLUE_SIZE, 8,
    134             EGL_ALPHA_SIZE, 8,
    135             EGL_DEPTH_SIZE, 0,
    136             EGL_STENCIL_SIZE, 0,
    137             EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
    138             EGL_CONFIG_CAVEAT, EGL_NONE,
    139             EGL_NONE
    140         };
    141     }
    142 
    143     /**
    144      * Prepare an EglSurface.
    145      * @param surfaceHolder surface holder.
    146      * @return true if EglSurface is ready.
    147      */
    148     public boolean createEglSurface(SurfaceHolder surfaceHolder) {
    149         mEglSurface = eglCreateWindowSurface(mEglDisplay, mEglConfig, surfaceHolder, null, 0);
    150         if (mEglSurface == null || mEglSurface == EGL_NO_SURFACE) {
    151             Log.w(TAG, "createWindowSurface failed: " + GLUtils.getEGLErrorString(eglGetError()));
    152             return false;
    153         }
    154 
    155         if (!eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
    156             Log.w(TAG, "eglMakeCurrent failed: " + GLUtils.getEGLErrorString(eglGetError()));
    157             return false;
    158         }
    159 
    160         return true;
    161     }
    162 
    163     /**
    164      * Destroy EglSurface.
    165      */
    166     public void destroyEglSurface() {
    167         if (hasEglSurface()) {
    168             eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    169             eglDestroySurface(mEglDisplay, mEglSurface);
    170             mEglSurface = null;
    171         }
    172     }
    173 
    174     /**
    175      * Check if we have a valid EglSurface.
    176      * @return true if EglSurface is ready.
    177      */
    178     public boolean hasEglSurface() {
    179         return mEglSurface != null && mEglSurface != EGL_NO_SURFACE;
    180     }
    181 
    182     /**
    183      * Prepare EglContext.
    184      * @return true if EglContext is ready.
    185      */
    186     public boolean createEglContext() {
    187         int[] attrib_list = new int[] {EGL_CONTEXT_CLIENT_VERSION, 2,
    188                 EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_LOW_IMG, EGL_NONE};
    189         mEglContext = eglCreateContext(mEglDisplay, mEglConfig, EGL_NO_CONTEXT, attrib_list, 0);
    190         if (mEglContext == EGL_NO_CONTEXT) {
    191             Log.w(TAG, "eglCreateContext failed: " + GLUtils.getEGLErrorString(eglGetError()));
    192             return false;
    193         }
    194         return true;
    195     }
    196 
    197     /**
    198      * Destroy EglContext.
    199      */
    200     public void destroyEglContext() {
    201         if (hasEglContext()) {
    202             eglDestroyContext(mEglDisplay, mEglContext);
    203             mEglContext = null;
    204         }
    205     }
    206 
    207     /**
    208      * Check if we have EglContext.
    209      * @return true if EglContext is ready.
    210      */
    211     public boolean hasEglContext() {
    212         return mEglContext != null;
    213     }
    214 
    215     /**
    216      * Swap buffer to display.
    217      * @return true if swap successfully.
    218      */
    219     public boolean swapBuffer() {
    220         boolean status = eglSwapBuffers(mEglDisplay, mEglSurface);
    221         int error = eglGetError();
    222         if (error != EGL_SUCCESS) {
    223             Log.w(TAG, "eglSwapBuffers failed: " + GLUtils.getEGLErrorString(error));
    224         }
    225         return status;
    226     }
    227 
    228     /**
    229      * Destroy EglSurface and EglContext, then terminate EGL.
    230      */
    231     public void finish() {
    232         if (hasEglSurface()) {
    233             destroyEglSurface();
    234         }
    235         if (hasEglContext()) {
    236             destroyEglContext();
    237         }
    238         eglTerminate(mEglDisplay);
    239         mEglReady = false;
    240     }
    241 
    242     /**
    243      * Called to dump current state.
    244      * @param prefix prefix.
    245      * @param fd fd.
    246      * @param out out.
    247      * @param args args.
    248      */
    249     public void dump(String prefix, FileDescriptor fd, PrintWriter out, String[] args) {
    250         String eglVersion = mEglVersion[0] + "." + mEglVersion[1];
    251         out.print(prefix); out.print("EGL version="); out.print(eglVersion);
    252         out.print(", "); out.print("EGL ready="); out.print(mEglReady);
    253         out.print(", "); out.print("has EglContext="); out.print(hasEglContext());
    254         out.print(", "); out.print("has EglSurface="); out.println(hasEglSurface());
    255 
    256         int[] configs = getConfig();
    257         StringBuilder sb = new StringBuilder();
    258         sb.append('{');
    259         for (int egl : configs) {
    260             sb.append("0x").append(Integer.toHexString(egl)).append(",");
    261         }
    262         sb.setCharAt(sb.length() - 1, '}');
    263         out.print(prefix); out.print("EglConfig="); out.println(sb.toString());
    264     }
    265 }
    266