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