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