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 */ init(SurfaceHolder surfaceHolder)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 chooseEglConfig()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 getConfig()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 */ createEglSurface(SurfaceHolder surfaceHolder)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 */ destroyEglSurface()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 */ hasEglSurface()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 */ createEglContext()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 */ destroyEglContext()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 */ hasEglContext()211 public boolean hasEglContext() { 212 return mEglContext != null; 213 } 214 215 /** 216 * Swap buffer to display. 217 * @return true if swap successfully. 218 */ swapBuffer()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 */ finish()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 */ dump(String prefix, FileDescriptor fd, PrintWriter out, String[] args)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