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", mBLASTSurfaceControl, 647 mDisplayWidth, mDisplayHeight, PixelFormat.TRANSLUCENT); 648 mSurface = mBLASTBufferQueue.createSurface(); 649 } 650 return true; 651 } 652 653 private boolean createEglContext(boolean isProtected) { 654 if (mEglDisplay == null) { 655 mEglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY); 656 if (mEglDisplay == EGL14.EGL_NO_DISPLAY) { 657 logEglError("eglGetDisplay"); 658 return false; 659 } 660 661 int[] version = new int[2]; 662 if (!EGL14.eglInitialize(mEglDisplay, version, 0, version, 1)) { 663 mEglDisplay = null; 664 logEglError("eglInitialize"); 665 return false; 666 } 667 } 668 669 if (mEglConfig == null) { 670 int[] eglConfigAttribList = new int[] { 671 EGL14.EGL_RENDERABLE_TYPE, 672 EGL14.EGL_OPENGL_ES2_BIT, 673 EGL14.EGL_RED_SIZE, 8, 674 EGL14.EGL_GREEN_SIZE, 8, 675 EGL14.EGL_BLUE_SIZE, 8, 676 EGL14.EGL_ALPHA_SIZE, 8, 677 EGL14.EGL_NONE 678 }; 679 int[] numEglConfigs = new int[1]; 680 EGLConfig[] eglConfigs = new EGLConfig[1]; 681 if (!EGL14.eglChooseConfig(mEglDisplay, eglConfigAttribList, 0, 682 eglConfigs, 0, eglConfigs.length, numEglConfigs, 0)) { 683 logEglError("eglChooseConfig"); 684 return false; 685 } 686 if (numEglConfigs[0] <= 0) { 687 Slog.e(TAG, "no valid config found"); 688 return false; 689 } 690 691 mEglConfig = eglConfigs[0]; 692 } 693 694 // The old context needs to be destroyed if the protected flag has changed. The context will 695 // be recreated based on the protected flag 696 if (mEglContext != null && isProtected != mLastWasProtectedContent) { 697 EGL14.eglDestroyContext(mEglDisplay, mEglContext); 698 mEglContext = null; 699 } 700 701 if (mEglContext == null) { 702 int[] eglContextAttribList = new int[] { 703 EGL14.EGL_CONTEXT_CLIENT_VERSION, 2, 704 EGL14.EGL_NONE, EGL14.EGL_NONE, 705 EGL14.EGL_NONE 706 }; 707 if (isProtected) { 708 eglContextAttribList[2] = EGL_PROTECTED_CONTENT_EXT; 709 eglContextAttribList[3] = EGL14.EGL_TRUE; 710 } 711 mEglContext = EGL14.eglCreateContext(mEglDisplay, mEglConfig, EGL14.EGL_NO_CONTEXT, 712 eglContextAttribList, 0); 713 if (mEglContext == null) { 714 logEglError("eglCreateContext"); 715 return false; 716 } 717 } 718 return true; 719 } 720 721 private boolean createEglSurface(boolean isProtected, boolean isWideColor) { 722 // The old surface needs to be destroyed if either the protected flag or wide color flag has 723 // changed. The surface will be recreated based on the new flags. 724 boolean didContentAttributesChange = 725 isProtected != mLastWasProtectedContent || isWideColor != mLastWasWideColor; 726 if (mEglSurface != null && didContentAttributesChange) { 727 EGL14.eglDestroySurface(mEglDisplay, mEglSurface); 728 mEglSurface = null; 729 } 730 731 if (mEglSurface == null) { 732 int[] eglSurfaceAttribList = new int[] { 733 EGL14.EGL_NONE, 734 EGL14.EGL_NONE, 735 EGL14.EGL_NONE, 736 EGL14.EGL_NONE, 737 EGL14.EGL_NONE 738 }; 739 740 int index = 0; 741 // If the current display is in wide color, then so is the screenshot. 742 if (isWideColor) { 743 eglSurfaceAttribList[index++] = EGL_GL_COLORSPACE_KHR; 744 eglSurfaceAttribList[index++] = EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT; 745 } 746 if (isProtected) { 747 eglSurfaceAttribList[index++] = EGL_PROTECTED_CONTENT_EXT; 748 eglSurfaceAttribList[index] = EGL14.EGL_TRUE; 749 } 750 // turn our SurfaceControl into a Surface 751 mEglSurface = EGL14.eglCreateWindowSurface(mEglDisplay, mEglConfig, mSurface, 752 eglSurfaceAttribList, 0); 753 if (mEglSurface == null) { 754 logEglError("eglCreateWindowSurface"); 755 return false; 756 } 757 } 758 return true; 759 } 760 761 private void destroyEglSurface() { 762 if (mEglSurface != null) { 763 if (!EGL14.eglDestroySurface(mEglDisplay, mEglSurface)) { 764 logEglError("eglDestroySurface"); 765 } 766 mEglSurface = null; 767 } 768 } 769 770 private void destroySurface() { 771 if (mSurfaceControl != null) { 772 mSurfaceLayout.dispose(); 773 mSurfaceLayout = null; 774 mTransaction.remove(mSurfaceControl).apply(); 775 if (mSurface != null) { 776 mSurface.release(); 777 mSurface = null; 778 } 779 780 if (mBLASTSurfaceControl != null) { 781 mBLASTSurfaceControl.release(); 782 mBLASTSurfaceControl = null; 783 mBLASTBufferQueue.destroy(); 784 mBLASTBufferQueue = null; 785 } 786 787 mSurfaceControl = null; 788 mSurfaceVisible = false; 789 mSurfaceAlpha = 0f; 790 } 791 } 792 793 private boolean showSurface(float alpha) { 794 if (!mSurfaceVisible || mSurfaceAlpha != alpha) { 795 mTransaction.setLayer(mSurfaceControl, COLOR_FADE_LAYER) 796 .setAlpha(mSurfaceControl, alpha) 797 .show(mSurfaceControl) 798 .apply(); 799 mSurfaceVisible = true; 800 mSurfaceAlpha = alpha; 801 } 802 return true; 803 } 804 805 private boolean attachEglContext() { 806 if (mEglSurface == null) { 807 return false; 808 } 809 if (!EGL14.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) { 810 logEglError("eglMakeCurrent"); 811 return false; 812 } 813 return true; 814 } 815 816 private void detachEglContext() { 817 if (mEglDisplay != null) { 818 EGL14.eglMakeCurrent(mEglDisplay, 819 EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT); 820 } 821 } 822 823 private void destroyEglContext() { 824 if (mEglDisplay != null && mEglContext != null) { 825 EGL14.eglDestroyContext(mEglDisplay, mEglContext); 826 } 827 } 828 829 private static FloatBuffer createNativeFloatBuffer(int size) { 830 ByteBuffer bb = ByteBuffer.allocateDirect(size * 4); 831 bb.order(ByteOrder.nativeOrder()); 832 return bb.asFloatBuffer(); 833 } 834 835 private static void logEglError(String func) { 836 Slog.e(TAG, func + " failed: error " + EGL14.eglGetError(), new Throwable()); 837 } 838 839 private static boolean checkGlErrors(String func) { 840 return checkGlErrors(func, true); 841 } 842 843 private static boolean checkGlErrors(String func, boolean log) { 844 boolean hadError = false; 845 int error; 846 while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) { 847 if (log) { 848 Slog.e(TAG, func + " failed: error " + error, new Throwable()); 849 } 850 hadError = true; 851 } 852 return hadError; 853 } 854 855 public void dump(PrintWriter pw) { 856 pw.println(); 857 pw.println("Color Fade State:"); 858 pw.println(" mPrepared=" + mPrepared); 859 pw.println(" mMode=" + mMode); 860 pw.println(" mDisplayLayerStack=" + mDisplayLayerStack); 861 pw.println(" mDisplayWidth=" + mDisplayWidth); 862 pw.println(" mDisplayHeight=" + mDisplayHeight); 863 pw.println(" mSurfaceVisible=" + mSurfaceVisible); 864 pw.println(" mSurfaceAlpha=" + mSurfaceAlpha); 865 } 866 867 /** 868 * Keeps a surface aligned with the natural orientation of the device. 869 * Updates the position and transformation of the matrix whenever the display 870 * is rotated. This is a little tricky because the display transaction 871 * callback can be invoked on any thread, not necessarily the thread that 872 * owns the color fade. 873 */ 874 private static final class NaturalSurfaceLayout implements DisplayTransactionListener { 875 private final DisplayManagerInternal mDisplayManagerInternal; 876 private final int mDisplayId; 877 private SurfaceControl mSurfaceControl; 878 879 public NaturalSurfaceLayout(DisplayManagerInternal displayManagerInternal, 880 int displayId, SurfaceControl surfaceControl) { 881 mDisplayManagerInternal = displayManagerInternal; 882 mDisplayId = displayId; 883 mSurfaceControl = surfaceControl; 884 mDisplayManagerInternal.registerDisplayTransactionListener(this); 885 } 886 887 public void dispose() { 888 synchronized (this) { 889 mSurfaceControl = null; 890 } 891 mDisplayManagerInternal.unregisterDisplayTransactionListener(this); 892 } 893 894 @Override 895 public void onDisplayTransaction(Transaction t) { 896 synchronized (this) { 897 if (mSurfaceControl == null) { 898 return; 899 } 900 901 DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId); 902 if (displayInfo == null) { 903 // displayInfo can be null if the associated display has been removed. There 904 // is a delay between the display being removed and ColorFade being dismissed. 905 return; 906 } 907 908 switch (displayInfo.rotation) { 909 case Surface.ROTATION_0: 910 t.setPosition(mSurfaceControl, 0, 0); 911 t.setMatrix(mSurfaceControl, 1, 0, 0, 1); 912 break; 913 case Surface.ROTATION_90: 914 t.setPosition(mSurfaceControl, 0, displayInfo.logicalHeight); 915 t.setMatrix(mSurfaceControl, 0, -1, 1, 0); 916 break; 917 case Surface.ROTATION_180: 918 t.setPosition(mSurfaceControl, displayInfo.logicalWidth, 919 displayInfo.logicalHeight); 920 t.setMatrix(mSurfaceControl, -1, 0, 0, -1); 921 break; 922 case Surface.ROTATION_270: 923 t.setPosition(mSurfaceControl, displayInfo.logicalWidth, 0); 924 t.setMatrix(mSurfaceControl, 0, 1, -1, 0); 925 break; 926 } 927 } 928 } 929 } 930 } 931