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