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