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