1 /* 2 * Copyright (C) 2010 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 18 package android.view; 19 20 import android.content.ComponentCallbacks2; 21 import android.graphics.Paint; 22 import android.graphics.Rect; 23 import android.graphics.SurfaceTexture; 24 import android.opengl.EGL14; 25 import android.opengl.GLUtils; 26 import android.opengl.ManagedEGLContext; 27 import android.os.Handler; 28 import android.os.Looper; 29 import android.os.SystemClock; 30 import android.os.SystemProperties; 31 import android.os.Trace; 32 import android.util.Log; 33 import com.google.android.gles_jni.EGLImpl; 34 35 import javax.microedition.khronos.egl.EGL10; 36 import javax.microedition.khronos.egl.EGL11; 37 import javax.microedition.khronos.egl.EGLConfig; 38 import javax.microedition.khronos.egl.EGLContext; 39 import javax.microedition.khronos.egl.EGLDisplay; 40 import javax.microedition.khronos.egl.EGLSurface; 41 import javax.microedition.khronos.opengles.GL; 42 43 import java.io.File; 44 import java.io.PrintWriter; 45 import java.util.concurrent.locks.ReentrantLock; 46 47 import static javax.microedition.khronos.egl.EGL10.*; 48 49 /** 50 * Interface for rendering a ViewAncestor using hardware acceleration. 51 * 52 * @hide 53 */ 54 public abstract class HardwareRenderer { 55 static final String LOG_TAG = "HardwareRenderer"; 56 57 /** 58 * Name of the file that holds the shaders cache. 59 */ 60 private static final String CACHE_PATH_SHADERS = "com.android.opengl.shaders_cache"; 61 62 /** 63 * Turn on to only refresh the parts of the screen that need updating. 64 * When turned on the property defined by {@link #RENDER_DIRTY_REGIONS_PROPERTY} 65 * must also have the value "true". 66 */ 67 public static final boolean RENDER_DIRTY_REGIONS = true; 68 69 /** 70 * System property used to enable or disable dirty regions invalidation. 71 * This property is only queried if {@link #RENDER_DIRTY_REGIONS} is true. 72 * The default value of this property is assumed to be true. 73 * 74 * Possible values: 75 * "true", to enable partial invalidates 76 * "false", to disable partial invalidates 77 */ 78 static final String RENDER_DIRTY_REGIONS_PROPERTY = "debug.hwui.render_dirty_regions"; 79 80 /** 81 * System property used to enable or disable vsync. 82 * The default value of this property is assumed to be false. 83 * 84 * Possible values: 85 * "true", to disable vsync 86 * "false", to enable vsync 87 */ 88 static final String DISABLE_VSYNC_PROPERTY = "debug.hwui.disable_vsync"; 89 90 /** 91 * System property used to enable or disable hardware rendering profiling. 92 * The default value of this property is assumed to be false. 93 * 94 * When profiling is enabled, the adb shell dumpsys gfxinfo command will 95 * output extra information about the time taken to execute by the last 96 * frames. 97 * 98 * Possible values: 99 * "true", to enable profiling 100 * "false", to disable profiling 101 * 102 * @hide 103 */ 104 public static final String PROFILE_PROPERTY = "debug.hwui.profile"; 105 106 /** 107 * System property used to specify the number of frames to be used 108 * when doing hardware rendering profiling. 109 * The default value of this property is #PROFILE_MAX_FRAMES. 110 * 111 * When profiling is enabled, the adb shell dumpsys gfxinfo command will 112 * output extra information about the time taken to execute by the last 113 * frames. 114 * 115 * Possible values: 116 * "60", to set the limit of frames to 60 117 */ 118 static final String PROFILE_MAXFRAMES_PROPERTY = "debug.hwui.profile.maxframes"; 119 120 /** 121 * System property used to debug EGL configuration choice. 122 * 123 * Possible values: 124 * "choice", print the chosen configuration only 125 * "all", print all possible configurations 126 */ 127 static final String PRINT_CONFIG_PROPERTY = "debug.hwui.print_config"; 128 129 /** 130 * Turn on to draw dirty regions every other frame. 131 * 132 * Possible values: 133 * "true", to enable dirty regions debugging 134 * "false", to disable dirty regions debugging 135 * 136 * @hide 137 */ 138 public static final String DEBUG_DIRTY_REGIONS_PROPERTY = "debug.hwui.show_dirty_regions"; 139 140 /** 141 * Turn on to flash hardware layers when they update. 142 * 143 * Possible values: 144 * "true", to enable hardware layers updates debugging 145 * "false", to disable hardware layers updates debugging 146 * 147 * @hide 148 */ 149 public static final String DEBUG_SHOW_LAYERS_UPDATES_PROPERTY = 150 "debug.hwui.show_layers_updates"; 151 152 /** 153 * Turn on to show overdraw level. 154 * 155 * Possible values: 156 * "true", to enable overdraw debugging 157 * "false", to disable overdraw debugging 158 * 159 * @hide 160 */ 161 public static final String DEBUG_SHOW_OVERDRAW_PROPERTY = "debug.hwui.show_overdraw"; 162 163 /** 164 * A process can set this flag to false to prevent the use of hardware 165 * rendering. 166 * 167 * @hide 168 */ 169 public static boolean sRendererDisabled = false; 170 171 /** 172 * Further hardware renderer disabling for the system process. 173 * 174 * @hide 175 */ 176 public static boolean sSystemRendererDisabled = false; 177 178 /** 179 * Number of frames to profile. 180 */ 181 private static final int PROFILE_MAX_FRAMES = 128; 182 183 /** 184 * Number of floats per profiled frame. 185 */ 186 private static final int PROFILE_FRAME_DATA_COUNT = 3; 187 188 private boolean mEnabled; 189 private boolean mRequested = true; 190 191 /** 192 * Invoke this method to disable hardware rendering in the current process. 193 * 194 * @hide 195 */ disable(boolean system)196 public static void disable(boolean system) { 197 sRendererDisabled = true; 198 if (system) { 199 sSystemRendererDisabled = true; 200 } 201 } 202 203 /** 204 * Indicates whether hardware acceleration is available under any form for 205 * the view hierarchy. 206 * 207 * @return True if the view hierarchy can potentially be hardware accelerated, 208 * false otherwise 209 */ isAvailable()210 public static boolean isAvailable() { 211 return GLES20Canvas.isAvailable(); 212 } 213 214 /** 215 * Destroys the hardware rendering context. 216 * 217 * @param full If true, destroys all associated resources. 218 */ destroy(boolean full)219 abstract void destroy(boolean full); 220 221 /** 222 * Initializes the hardware renderer for the specified surface. 223 * 224 * @param surface The surface to hardware accelerate 225 * 226 * @return True if the initialization was successful, false otherwise. 227 */ initialize(Surface surface)228 abstract boolean initialize(Surface surface) throws Surface.OutOfResourcesException; 229 230 /** 231 * Updates the hardware renderer for the specified surface. 232 * 233 * @param surface The surface to hardware accelerate 234 */ updateSurface(Surface surface)235 abstract void updateSurface(Surface surface) throws Surface.OutOfResourcesException; 236 237 /** 238 * Destroys the layers used by the specified view hierarchy. 239 * 240 * @param view The root of the view hierarchy 241 */ destroyLayers(View view)242 abstract void destroyLayers(View view); 243 244 /** 245 * Destroys all hardware rendering resources associated with the specified 246 * view hierarchy. 247 * 248 * @param view The root of the view hierarchy 249 */ destroyHardwareResources(View view)250 abstract void destroyHardwareResources(View view); 251 252 /** 253 * This method should be invoked whenever the current hardware renderer 254 * context should be reset. 255 * 256 * @param surface The surface to hardware accelerate 257 */ invalidate(Surface surface)258 abstract void invalidate(Surface surface); 259 260 /** 261 * This method should be invoked to ensure the hardware renderer is in 262 * valid state (for instance, to ensure the correct EGL context is bound 263 * to the current thread.) 264 * 265 * @return true if the renderer is now valid, false otherwise 266 */ validate()267 abstract boolean validate(); 268 269 /** 270 * This method ensures the hardware renderer is in a valid state 271 * before executing the specified action. 272 * 273 * This method will attempt to set a valid state even if the window 274 * the renderer is attached to was destroyed. 275 * 276 * @return true if the action was run 277 */ safelyRun(Runnable action)278 abstract boolean safelyRun(Runnable action); 279 280 /** 281 * Setup the hardware renderer for drawing. This is called whenever the 282 * size of the target surface changes or when the surface is first created. 283 * 284 * @param width Width of the drawing surface. 285 * @param height Height of the drawing surface. 286 */ setup(int width, int height)287 abstract void setup(int width, int height); 288 289 /** 290 * Gets the current width of the surface. This is the width that the surface 291 * was last set to in a call to {@link #setup(int, int)}. 292 * 293 * @return the current width of the surface 294 */ getWidth()295 abstract int getWidth(); 296 297 /** 298 * Gets the current height of the surface. This is the height that the surface 299 * was last set to in a call to {@link #setup(int, int)}. 300 * 301 * @return the current width of the surface 302 */ getHeight()303 abstract int getHeight(); 304 305 /** 306 * Gets the current canvas associated with this HardwareRenderer. 307 * 308 * @return the current HardwareCanvas 309 */ getCanvas()310 abstract HardwareCanvas getCanvas(); 311 312 /** 313 * Outputs extra debugging information in the specified file descriptor. 314 * @param pw 315 */ dumpGfxInfo(PrintWriter pw)316 abstract void dumpGfxInfo(PrintWriter pw); 317 318 /** 319 * Outputs the total number of frames rendered (used for fps calculations) 320 * 321 * @return the number of frames rendered 322 */ getFrameCount()323 abstract long getFrameCount(); 324 325 /** 326 * Sets the directory to use as a persistent storage for hardware rendering 327 * resources. 328 * 329 * @param cacheDir A directory the current process can write to 330 */ setupDiskCache(File cacheDir)331 public static void setupDiskCache(File cacheDir) { 332 nSetupShadersDiskCache(new File(cacheDir, CACHE_PATH_SHADERS).getAbsolutePath()); 333 } 334 nSetupShadersDiskCache(String cacheFile)335 private static native void nSetupShadersDiskCache(String cacheFile); 336 337 /** 338 * Notifies EGL that the frame is about to be rendered. 339 * @param size 340 */ beginFrame(int[] size)341 private static void beginFrame(int[] size) { 342 nBeginFrame(size); 343 } 344 nBeginFrame(int[] size)345 private static native void nBeginFrame(int[] size); 346 347 /** 348 * Preserves the back buffer of the current surface after a buffer swap. 349 * Calling this method sets the EGL_SWAP_BEHAVIOR attribute of the current 350 * surface to EGL_BUFFER_PRESERVED. Calling this method requires an EGL 351 * config that supports EGL_SWAP_BEHAVIOR_PRESERVED_BIT. 352 * 353 * @return True if the swap behavior was successfully changed, 354 * false otherwise. 355 */ preserveBackBuffer()356 static boolean preserveBackBuffer() { 357 return nPreserveBackBuffer(); 358 } 359 nPreserveBackBuffer()360 private static native boolean nPreserveBackBuffer(); 361 362 /** 363 * Indicates whether the current surface preserves its back buffer 364 * after a buffer swap. 365 * 366 * @return True, if the surface's EGL_SWAP_BEHAVIOR is EGL_BUFFER_PRESERVED, 367 * false otherwise 368 */ isBackBufferPreserved()369 static boolean isBackBufferPreserved() { 370 return nIsBackBufferPreserved(); 371 } 372 nIsBackBufferPreserved()373 private static native boolean nIsBackBufferPreserved(); 374 375 /** 376 * Disables v-sync. For performance testing only. 377 */ disableVsync()378 static void disableVsync() { 379 nDisableVsync(); 380 } 381 nDisableVsync()382 private static native void nDisableVsync(); 383 384 /** 385 * Indicates that the specified hardware layer needs to be updated 386 * as soon as possible. 387 * 388 * @param layer The hardware layer that needs an update 389 */ pushLayerUpdate(HardwareLayer layer)390 abstract void pushLayerUpdate(HardwareLayer layer); 391 392 /** 393 * Interface used to receive callbacks whenever a view is drawn by 394 * a hardware renderer instance. 395 */ 396 interface HardwareDrawCallbacks { 397 /** 398 * Invoked before a view is drawn by a hardware renderer. 399 * 400 * @param canvas The Canvas used to render the view. 401 */ onHardwarePreDraw(HardwareCanvas canvas)402 void onHardwarePreDraw(HardwareCanvas canvas); 403 404 /** 405 * Invoked after a view is drawn by a hardware renderer. 406 * 407 * @param canvas The Canvas used to render the view. 408 */ onHardwarePostDraw(HardwareCanvas canvas)409 void onHardwarePostDraw(HardwareCanvas canvas); 410 } 411 412 /** 413 * Draws the specified view. 414 * 415 * @param view The view to draw. 416 * @param attachInfo AttachInfo tied to the specified view. 417 * @param callbacks Callbacks invoked when drawing happens. 418 * @param dirty The dirty rectangle to update, can be null. 419 * 420 * @return true if the dirty rect was ignored, false otherwise 421 */ draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks, Rect dirty)422 abstract boolean draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks, 423 Rect dirty); 424 425 /** 426 * Creates a new display list that can be used to record batches of 427 * drawing operations. 428 * 429 * @param name The name of the display list, used for debugging purpose. 430 * May be null 431 * 432 * @return A new display list. 433 */ createDisplayList(String name)434 public abstract DisplayList createDisplayList(String name); 435 436 /** 437 * Creates a new hardware layer. A hardware layer built by calling this 438 * method will be treated as a texture layer, instead of as a render target. 439 * 440 * @param isOpaque Whether the layer should be opaque or not 441 * 442 * @return A hardware layer 443 */ createHardwareLayer(boolean isOpaque)444 abstract HardwareLayer createHardwareLayer(boolean isOpaque); 445 446 /** 447 * Creates a new hardware layer. 448 * 449 * @param width The minimum width of the layer 450 * @param height The minimum height of the layer 451 * @param isOpaque Whether the layer should be opaque or not 452 * 453 * @return A hardware layer 454 */ createHardwareLayer(int width, int height, boolean isOpaque)455 abstract HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque); 456 457 /** 458 * Creates a new {@link SurfaceTexture} that can be used to render into the 459 * specified hardware layer. 460 * 461 * 462 * @param layer The layer to render into using a {@link android.graphics.SurfaceTexture} 463 * 464 * @return A {@link SurfaceTexture} 465 */ createSurfaceTexture(HardwareLayer layer)466 abstract SurfaceTexture createSurfaceTexture(HardwareLayer layer); 467 468 /** 469 * Sets the {@link android.graphics.SurfaceTexture} that will be used to 470 * render into the specified hardware layer. 471 * 472 * @param layer The layer to render into using a {@link android.graphics.SurfaceTexture} 473 * @param surfaceTexture The {@link android.graphics.SurfaceTexture} to use for the layer 474 */ setSurfaceTexture(HardwareLayer layer, SurfaceTexture surfaceTexture)475 abstract void setSurfaceTexture(HardwareLayer layer, SurfaceTexture surfaceTexture); 476 477 /** 478 * Detaches the specified functor from the current functor execution queue. 479 * 480 * @param functor The native functor to remove from the execution queue. 481 * 482 * @see HardwareCanvas#callDrawGLFunction(int) 483 * @see #attachFunctor(android.view.View.AttachInfo, int) 484 */ detachFunctor(int functor)485 abstract void detachFunctor(int functor); 486 487 /** 488 * Schedules the specified functor in the functors execution queue. 489 * 490 * @param attachInfo AttachInfo tied to this renderer. 491 * @param functor The native functor to insert in the execution queue. 492 * 493 * @see HardwareCanvas#callDrawGLFunction(int) 494 * @see #detachFunctor(int) 495 * 496 * @return true if the functor was attached successfully 497 */ attachFunctor(View.AttachInfo attachInfo, int functor)498 abstract boolean attachFunctor(View.AttachInfo attachInfo, int functor); 499 500 /** 501 * Initializes the hardware renderer for the specified surface and setup the 502 * renderer for drawing, if needed. This is invoked when the ViewAncestor has 503 * potentially lost the hardware renderer. The hardware renderer should be 504 * reinitialized and setup when the render {@link #isRequested()} and 505 * {@link #isEnabled()}. 506 * 507 * @param width The width of the drawing surface. 508 * @param height The height of the drawing surface. 509 * @param surface The surface to hardware accelerate 510 * 511 * @return true if the surface was initialized, false otherwise. Returning 512 * false might mean that the surface was already initialized. 513 */ initializeIfNeeded(int width, int height, Surface surface)514 boolean initializeIfNeeded(int width, int height, Surface surface) 515 throws Surface.OutOfResourcesException { 516 if (isRequested()) { 517 // We lost the gl context, so recreate it. 518 if (!isEnabled()) { 519 if (initialize(surface)) { 520 setup(width, height); 521 return true; 522 } 523 } 524 } 525 return false; 526 } 527 528 /** 529 * Creates a hardware renderer using OpenGL. 530 * 531 * @param glVersion The version of OpenGL to use (1 for OpenGL 1, 11 for OpenGL 1.1, etc.) 532 * @param translucent True if the surface is translucent, false otherwise 533 * 534 * @return A hardware renderer backed by OpenGL. 535 */ createGlRenderer(int glVersion, boolean translucent)536 static HardwareRenderer createGlRenderer(int glVersion, boolean translucent) { 537 switch (glVersion) { 538 case 2: 539 return Gl20Renderer.create(translucent); 540 } 541 throw new IllegalArgumentException("Unknown GL version: " + glVersion); 542 } 543 544 /** 545 * Invoke this method when the system is running out of memory. This 546 * method will attempt to recover as much memory as possible, based on 547 * the specified hint. 548 * 549 * @param level Hint about the amount of memory that should be trimmed, 550 * see {@link android.content.ComponentCallbacks} 551 */ trimMemory(int level)552 static void trimMemory(int level) { 553 startTrimMemory(level); 554 endTrimMemory(); 555 } 556 557 /** 558 * Starts the process of trimming memory. Usually this call will setup 559 * hardware rendering context and reclaim memory.Extra cleanup might 560 * be required by calling {@link #endTrimMemory()}. 561 * 562 * @param level Hint about the amount of memory that should be trimmed, 563 * see {@link android.content.ComponentCallbacks} 564 */ startTrimMemory(int level)565 static void startTrimMemory(int level) { 566 Gl20Renderer.startTrimMemory(level); 567 } 568 569 /** 570 * Finishes the process of trimming memory. This method will usually 571 * cleanup special resources used by the memory trimming process. 572 */ endTrimMemory()573 static void endTrimMemory() { 574 Gl20Renderer.endTrimMemory(); 575 } 576 577 /** 578 * Indicates whether hardware acceleration is currently enabled. 579 * 580 * @return True if hardware acceleration is in use, false otherwise. 581 */ isEnabled()582 boolean isEnabled() { 583 return mEnabled; 584 } 585 586 /** 587 * Indicates whether hardware acceleration is currently enabled. 588 * 589 * @param enabled True if the hardware renderer is in use, false otherwise. 590 */ setEnabled(boolean enabled)591 void setEnabled(boolean enabled) { 592 mEnabled = enabled; 593 } 594 595 /** 596 * Indicates whether hardware acceleration is currently request but not 597 * necessarily enabled yet. 598 * 599 * @return True if requested, false otherwise. 600 */ isRequested()601 boolean isRequested() { 602 return mRequested; 603 } 604 605 /** 606 * Indicates whether hardware acceleration is currently requested but not 607 * necessarily enabled yet. 608 * 609 * @return True to request hardware acceleration, false otherwise. 610 */ setRequested(boolean requested)611 void setRequested(boolean requested) { 612 mRequested = requested; 613 } 614 615 @SuppressWarnings({"deprecation"}) 616 static abstract class GlRenderer extends HardwareRenderer { 617 static final int SURFACE_STATE_ERROR = 0; 618 static final int SURFACE_STATE_SUCCESS = 1; 619 static final int SURFACE_STATE_UPDATED = 2; 620 621 static final int FUNCTOR_PROCESS_DELAY = 4; 622 623 static EGL10 sEgl; 624 static EGLDisplay sEglDisplay; 625 static EGLConfig sEglConfig; 626 static final Object[] sEglLock = new Object[0]; 627 int mWidth = -1, mHeight = -1; 628 629 static final ThreadLocal<ManagedEGLContext> sEglContextStorage 630 = new ThreadLocal<ManagedEGLContext>(); 631 632 EGLContext mEglContext; 633 Thread mEglThread; 634 635 EGLSurface mEglSurface; 636 637 GL mGl; 638 HardwareCanvas mCanvas; 639 640 long mFrameCount; 641 Paint mDebugPaint; 642 643 static boolean sDirtyRegions; 644 static final boolean sDirtyRegionsRequested; 645 static { 646 String dirtyProperty = SystemProperties.get(RENDER_DIRTY_REGIONS_PROPERTY, "true"); 647 //noinspection PointlessBooleanExpression,ConstantConditions 648 sDirtyRegions = RENDER_DIRTY_REGIONS && "true".equalsIgnoreCase(dirtyProperty); 649 sDirtyRegionsRequested = sDirtyRegions; 650 } 651 652 boolean mDirtyRegionsEnabled; 653 boolean mUpdateDirtyRegions; 654 655 final boolean mVsyncDisabled; 656 657 final boolean mProfileEnabled; 658 final float[] mProfileData; 659 final ReentrantLock mProfileLock; 660 int mProfileCurrentFrame = -PROFILE_FRAME_DATA_COUNT; 661 662 final boolean mDebugDirtyRegions; 663 final boolean mShowOverdraw; 664 665 final int mGlVersion; 666 final boolean mTranslucent; 667 668 private boolean mDestroyed; 669 670 private final Rect mRedrawClip = new Rect(); 671 672 private final int[] mSurfaceSize = new int[2]; 673 private final FunctorsRunnable mFunctorsRunnable = new FunctorsRunnable(); 674 GlRenderer(int glVersion, boolean translucent)675 GlRenderer(int glVersion, boolean translucent) { 676 mGlVersion = glVersion; 677 mTranslucent = translucent; 678 679 String property; 680 681 property = SystemProperties.get(DISABLE_VSYNC_PROPERTY, "false"); 682 mVsyncDisabled = "true".equalsIgnoreCase(property); 683 if (mVsyncDisabled) { 684 Log.d(LOG_TAG, "Disabling v-sync"); 685 } 686 687 property = SystemProperties.get(PROFILE_PROPERTY, "false"); 688 mProfileEnabled = "true".equalsIgnoreCase(property); 689 if (mProfileEnabled) { 690 Log.d(LOG_TAG, "Profiling hardware renderer"); 691 } 692 693 if (mProfileEnabled) { 694 property = SystemProperties.get(PROFILE_MAXFRAMES_PROPERTY, 695 Integer.toString(PROFILE_MAX_FRAMES)); 696 int maxProfileFrames = Integer.valueOf(property); 697 mProfileData = new float[maxProfileFrames * PROFILE_FRAME_DATA_COUNT]; 698 for (int i = 0; i < mProfileData.length; i += PROFILE_FRAME_DATA_COUNT) { 699 mProfileData[i] = mProfileData[i + 1] = mProfileData[i + 2] = -1; 700 } 701 702 mProfileLock = new ReentrantLock(); 703 } else { 704 mProfileData = null; 705 mProfileLock = null; 706 } 707 708 property = SystemProperties.get(DEBUG_DIRTY_REGIONS_PROPERTY, "false"); 709 mDebugDirtyRegions = "true".equalsIgnoreCase(property); 710 if (mDebugDirtyRegions) { 711 Log.d(LOG_TAG, "Debugging dirty regions"); 712 } 713 714 mShowOverdraw = SystemProperties.getBoolean( 715 HardwareRenderer.DEBUG_SHOW_OVERDRAW_PROPERTY, false); 716 } 717 718 @Override dumpGfxInfo(PrintWriter pw)719 void dumpGfxInfo(PrintWriter pw) { 720 if (mProfileEnabled) { 721 pw.printf("\n\tDraw\tProcess\tExecute\n"); 722 723 mProfileLock.lock(); 724 try { 725 for (int i = 0; i < mProfileData.length; i += PROFILE_FRAME_DATA_COUNT) { 726 if (mProfileData[i] < 0) { 727 break; 728 } 729 pw.printf("\t%3.2f\t%3.2f\t%3.2f\n", mProfileData[i], mProfileData[i + 1], 730 mProfileData[i + 2]); 731 mProfileData[i] = mProfileData[i + 1] = mProfileData[i + 2] = -1; 732 } 733 mProfileCurrentFrame = mProfileData.length; 734 } finally { 735 mProfileLock.unlock(); 736 } 737 } 738 } 739 740 @Override getFrameCount()741 long getFrameCount() { 742 return mFrameCount; 743 } 744 745 /** 746 * Indicates whether this renderer instance can track and update dirty regions. 747 */ hasDirtyRegions()748 boolean hasDirtyRegions() { 749 return mDirtyRegionsEnabled; 750 } 751 752 /** 753 * Checks for OpenGL errors. If an error has occured, {@link #destroy(boolean)} 754 * is invoked and the requested flag is turned off. The error code is 755 * also logged as a warning. 756 */ checkEglErrors()757 void checkEglErrors() { 758 if (isEnabled()) { 759 checkEglErrorsForced(); 760 } 761 } 762 checkEglErrorsForced()763 private void checkEglErrorsForced() { 764 int error = sEgl.eglGetError(); 765 if (error != EGL_SUCCESS) { 766 // something bad has happened revert to 767 // normal rendering. 768 Log.w(LOG_TAG, "EGL error: " + GLUtils.getEGLErrorString(error)); 769 fallback(error != EGL11.EGL_CONTEXT_LOST); 770 } 771 } 772 fallback(boolean fallback)773 private void fallback(boolean fallback) { 774 destroy(true); 775 if (fallback) { 776 // we'll try again if it was context lost 777 setRequested(false); 778 Log.w(LOG_TAG, "Mountain View, we've had a problem here. " 779 + "Switching back to software rendering."); 780 } 781 } 782 783 @Override initialize(Surface surface)784 boolean initialize(Surface surface) throws Surface.OutOfResourcesException { 785 if (isRequested() && !isEnabled()) { 786 initializeEgl(); 787 mGl = createEglSurface(surface); 788 mDestroyed = false; 789 790 if (mGl != null) { 791 int err = sEgl.eglGetError(); 792 if (err != EGL_SUCCESS) { 793 destroy(true); 794 setRequested(false); 795 } else { 796 if (mCanvas == null) { 797 mCanvas = createCanvas(); 798 } 799 if (mCanvas != null) { 800 setEnabled(true); 801 } else { 802 Log.w(LOG_TAG, "Hardware accelerated Canvas could not be created"); 803 } 804 } 805 806 return mCanvas != null; 807 } 808 } 809 return false; 810 } 811 812 @Override updateSurface(Surface surface)813 void updateSurface(Surface surface) throws Surface.OutOfResourcesException { 814 if (isRequested() && isEnabled()) { 815 createEglSurface(surface); 816 } 817 } 818 createCanvas()819 abstract HardwareCanvas createCanvas(); 820 getConfig(boolean dirtyRegions)821 abstract int[] getConfig(boolean dirtyRegions); 822 initializeEgl()823 void initializeEgl() { 824 synchronized (sEglLock) { 825 if (sEgl == null && sEglConfig == null) { 826 sEgl = (EGL10) EGLContext.getEGL(); 827 828 // Get to the default display. 829 sEglDisplay = sEgl.eglGetDisplay(EGL_DEFAULT_DISPLAY); 830 831 if (sEglDisplay == EGL_NO_DISPLAY) { 832 throw new RuntimeException("eglGetDisplay failed " 833 + GLUtils.getEGLErrorString(sEgl.eglGetError())); 834 } 835 836 // We can now initialize EGL for that display 837 int[] version = new int[2]; 838 if (!sEgl.eglInitialize(sEglDisplay, version)) { 839 throw new RuntimeException("eglInitialize failed " + 840 GLUtils.getEGLErrorString(sEgl.eglGetError())); 841 } 842 843 checkEglErrorsForced(); 844 845 sEglConfig = chooseEglConfig(); 846 if (sEglConfig == null) { 847 // We tried to use EGL_SWAP_BEHAVIOR_PRESERVED_BIT, try again without 848 if (sDirtyRegions) { 849 sDirtyRegions = false; 850 sEglConfig = chooseEglConfig(); 851 if (sEglConfig == null) { 852 throw new RuntimeException("eglConfig not initialized"); 853 } 854 } else { 855 throw new RuntimeException("eglConfig not initialized"); 856 } 857 } 858 } 859 } 860 861 ManagedEGLContext managedContext = sEglContextStorage.get(); 862 mEglContext = managedContext != null ? managedContext.getContext() : null; 863 mEglThread = Thread.currentThread(); 864 865 if (mEglContext == null) { 866 mEglContext = createContext(sEgl, sEglDisplay, sEglConfig); 867 sEglContextStorage.set(createManagedContext(mEglContext)); 868 } 869 } 870 createManagedContext(EGLContext eglContext)871 abstract ManagedEGLContext createManagedContext(EGLContext eglContext); 872 chooseEglConfig()873 private EGLConfig chooseEglConfig() { 874 EGLConfig[] configs = new EGLConfig[1]; 875 int[] configsCount = new int[1]; 876 int[] configSpec = getConfig(sDirtyRegions); 877 878 // Debug 879 final String debug = SystemProperties.get(PRINT_CONFIG_PROPERTY, ""); 880 if ("all".equalsIgnoreCase(debug)) { 881 sEgl.eglChooseConfig(sEglDisplay, configSpec, null, 0, configsCount); 882 883 EGLConfig[] debugConfigs = new EGLConfig[configsCount[0]]; 884 sEgl.eglChooseConfig(sEglDisplay, configSpec, debugConfigs, 885 configsCount[0], configsCount); 886 887 for (EGLConfig config : debugConfigs) { 888 printConfig(config); 889 } 890 } 891 892 if (!sEgl.eglChooseConfig(sEglDisplay, configSpec, configs, 1, configsCount)) { 893 throw new IllegalArgumentException("eglChooseConfig failed " + 894 GLUtils.getEGLErrorString(sEgl.eglGetError())); 895 } else if (configsCount[0] > 0) { 896 if ("choice".equalsIgnoreCase(debug)) { 897 printConfig(configs[0]); 898 } 899 return configs[0]; 900 } 901 902 return null; 903 } 904 printConfig(EGLConfig config)905 private static void printConfig(EGLConfig config) { 906 int[] value = new int[1]; 907 908 Log.d(LOG_TAG, "EGL configuration " + config + ":"); 909 910 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_RED_SIZE, value); 911 Log.d(LOG_TAG, " RED_SIZE = " + value[0]); 912 913 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_GREEN_SIZE, value); 914 Log.d(LOG_TAG, " GREEN_SIZE = " + value[0]); 915 916 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_BLUE_SIZE, value); 917 Log.d(LOG_TAG, " BLUE_SIZE = " + value[0]); 918 919 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_ALPHA_SIZE, value); 920 Log.d(LOG_TAG, " ALPHA_SIZE = " + value[0]); 921 922 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_DEPTH_SIZE, value); 923 Log.d(LOG_TAG, " DEPTH_SIZE = " + value[0]); 924 925 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_STENCIL_SIZE, value); 926 Log.d(LOG_TAG, " STENCIL_SIZE = " + value[0]); 927 928 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_SAMPLE_BUFFERS, value); 929 Log.d(LOG_TAG, " SAMPLE_BUFFERS = " + value[0]); 930 931 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_SAMPLES, value); 932 Log.d(LOG_TAG, " SAMPLES = " + value[0]); 933 934 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_SURFACE_TYPE, value); 935 Log.d(LOG_TAG, " SURFACE_TYPE = 0x" + Integer.toHexString(value[0])); 936 937 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_CONFIG_CAVEAT, value); 938 Log.d(LOG_TAG, " CONFIG_CAVEAT = 0x" + Integer.toHexString(value[0])); 939 } 940 createEglSurface(Surface surface)941 GL createEglSurface(Surface surface) throws Surface.OutOfResourcesException { 942 // Check preconditions. 943 if (sEgl == null) { 944 throw new RuntimeException("egl not initialized"); 945 } 946 if (sEglDisplay == null) { 947 throw new RuntimeException("eglDisplay not initialized"); 948 } 949 if (sEglConfig == null) { 950 throw new RuntimeException("eglConfig not initialized"); 951 } 952 if (Thread.currentThread() != mEglThread) { 953 throw new IllegalStateException("HardwareRenderer cannot be used " 954 + "from multiple threads"); 955 } 956 957 // In case we need to destroy an existing surface 958 destroySurface(); 959 960 // Create an EGL surface we can render into. 961 if (!createSurface(surface)) { 962 return null; 963 } 964 965 initCaches(); 966 967 return mEglContext.getGL(); 968 } 969 enableDirtyRegions()970 private void enableDirtyRegions() { 971 // If mDirtyRegions is set, this means we have an EGL configuration 972 // with EGL_SWAP_BEHAVIOR_PRESERVED_BIT set 973 if (sDirtyRegions) { 974 if (!(mDirtyRegionsEnabled = preserveBackBuffer())) { 975 Log.w(LOG_TAG, "Backbuffer cannot be preserved"); 976 } 977 } else if (sDirtyRegionsRequested) { 978 // If mDirtyRegions is not set, our EGL configuration does not 979 // have EGL_SWAP_BEHAVIOR_PRESERVED_BIT; however, the default 980 // swap behavior might be EGL_BUFFER_PRESERVED, which means we 981 // want to set mDirtyRegions. We try to do this only if dirty 982 // regions were initially requested as part of the device 983 // configuration (see RENDER_DIRTY_REGIONS) 984 mDirtyRegionsEnabled = isBackBufferPreserved(); 985 } 986 } 987 initCaches()988 abstract void initCaches(); 989 createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig)990 EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) { 991 int[] attribs = { EGL14.EGL_CONTEXT_CLIENT_VERSION, mGlVersion, EGL_NONE }; 992 993 EGLContext context = egl.eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT, 994 mGlVersion != 0 ? attribs : null); 995 if (context == null || context == EGL_NO_CONTEXT) { 996 //noinspection ConstantConditions 997 throw new IllegalStateException( 998 "Could not create an EGL context. eglCreateContext failed with error: " + 999 GLUtils.getEGLErrorString(sEgl.eglGetError())); 1000 } 1001 return context; 1002 } 1003 1004 @Override destroy(boolean full)1005 void destroy(boolean full) { 1006 if (full && mCanvas != null) { 1007 mCanvas = null; 1008 } 1009 1010 if (!isEnabled() || mDestroyed) { 1011 setEnabled(false); 1012 return; 1013 } 1014 1015 destroySurface(); 1016 setEnabled(false); 1017 1018 mDestroyed = true; 1019 mGl = null; 1020 } 1021 destroySurface()1022 void destroySurface() { 1023 if (mEglSurface != null && mEglSurface != EGL_NO_SURFACE) { 1024 sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 1025 sEgl.eglDestroySurface(sEglDisplay, mEglSurface); 1026 mEglSurface = null; 1027 } 1028 } 1029 1030 @Override invalidate(Surface surface)1031 void invalidate(Surface surface) { 1032 // Cancels any existing buffer to ensure we'll get a buffer 1033 // of the right size before we call eglSwapBuffers 1034 sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 1035 1036 if (mEglSurface != null && mEglSurface != EGL_NO_SURFACE) { 1037 sEgl.eglDestroySurface(sEglDisplay, mEglSurface); 1038 mEglSurface = null; 1039 setEnabled(false); 1040 } 1041 1042 if (surface.isValid()) { 1043 if (!createSurface(surface)) { 1044 return; 1045 } 1046 1047 mUpdateDirtyRegions = true; 1048 1049 if (mCanvas != null) { 1050 setEnabled(true); 1051 } 1052 } 1053 } 1054 createSurface(Surface surface)1055 private boolean createSurface(Surface surface) { 1056 mEglSurface = sEgl.eglCreateWindowSurface(sEglDisplay, sEglConfig, surface, null); 1057 1058 if (mEglSurface == null || mEglSurface == EGL_NO_SURFACE) { 1059 int error = sEgl.eglGetError(); 1060 if (error == EGL_BAD_NATIVE_WINDOW) { 1061 Log.e(LOG_TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW."); 1062 return false; 1063 } 1064 throw new RuntimeException("createWindowSurface failed " 1065 + GLUtils.getEGLErrorString(error)); 1066 } 1067 1068 if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, mEglContext)) { 1069 throw new IllegalStateException("eglMakeCurrent failed " + 1070 GLUtils.getEGLErrorString(sEgl.eglGetError())); 1071 } 1072 1073 enableDirtyRegions(); 1074 1075 return true; 1076 } 1077 1078 @Override validate()1079 boolean validate() { 1080 return checkCurrent() != SURFACE_STATE_ERROR; 1081 } 1082 1083 @Override setup(int width, int height)1084 void setup(int width, int height) { 1085 if (validate()) { 1086 mCanvas.setViewport(width, height); 1087 mWidth = width; 1088 mHeight = height; 1089 } 1090 } 1091 1092 @Override getWidth()1093 int getWidth() { 1094 return mWidth; 1095 } 1096 1097 @Override getHeight()1098 int getHeight() { 1099 return mHeight; 1100 } 1101 1102 @Override getCanvas()1103 HardwareCanvas getCanvas() { 1104 return mCanvas; 1105 } 1106 canDraw()1107 boolean canDraw() { 1108 return mGl != null && mCanvas != null; 1109 } 1110 onPreDraw(Rect dirty)1111 int onPreDraw(Rect dirty) { 1112 return DisplayList.STATUS_DONE; 1113 } 1114 onPostDraw()1115 void onPostDraw() { 1116 } 1117 1118 class FunctorsRunnable implements Runnable { 1119 View.AttachInfo attachInfo; 1120 1121 @Override run()1122 public void run() { 1123 final HardwareRenderer renderer = attachInfo.mHardwareRenderer; 1124 if (renderer == null || !renderer.isEnabled() || renderer != GlRenderer.this) { 1125 return; 1126 } 1127 1128 final int surfaceState = checkCurrent(); 1129 if (surfaceState != SURFACE_STATE_ERROR) { 1130 int status = mCanvas.invokeFunctors(mRedrawClip); 1131 handleFunctorStatus(attachInfo, status); 1132 } 1133 } 1134 } 1135 1136 @Override draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks, Rect dirty)1137 boolean draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks, 1138 Rect dirty) { 1139 if (canDraw()) { 1140 if (!hasDirtyRegions()) { 1141 dirty = null; 1142 } 1143 attachInfo.mIgnoreDirtyState = true; 1144 attachInfo.mDrawingTime = SystemClock.uptimeMillis(); 1145 1146 view.mPrivateFlags |= View.PFLAG_DRAWN; 1147 1148 final int surfaceState = checkCurrent(); 1149 if (surfaceState != SURFACE_STATE_ERROR) { 1150 HardwareCanvas canvas = mCanvas; 1151 attachInfo.mHardwareCanvas = canvas; 1152 1153 if (mProfileEnabled) { 1154 mProfileLock.lock(); 1155 } 1156 1157 // We had to change the current surface and/or context, redraw everything 1158 if (surfaceState == SURFACE_STATE_UPDATED) { 1159 dirty = null; 1160 beginFrame(null); 1161 } else { 1162 int[] size = mSurfaceSize; 1163 beginFrame(size); 1164 1165 if (size[1] != mHeight || size[0] != mWidth) { 1166 mWidth = size[0]; 1167 mHeight = size[1]; 1168 1169 canvas.setViewport(mWidth, mHeight); 1170 1171 dirty = null; 1172 } 1173 } 1174 1175 int saveCount = 0; 1176 int status = DisplayList.STATUS_DONE; 1177 1178 try { 1179 view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED) 1180 == View.PFLAG_INVALIDATED; 1181 view.mPrivateFlags &= ~View.PFLAG_INVALIDATED; 1182 1183 long getDisplayListStartTime = 0; 1184 if (mProfileEnabled) { 1185 mProfileCurrentFrame += PROFILE_FRAME_DATA_COUNT; 1186 if (mProfileCurrentFrame >= mProfileData.length) { 1187 mProfileCurrentFrame = 0; 1188 } 1189 1190 getDisplayListStartTime = System.nanoTime(); 1191 } 1192 1193 canvas.clearLayerUpdates(); 1194 1195 DisplayList displayList; 1196 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList"); 1197 try { 1198 displayList = view.getDisplayList(); 1199 } finally { 1200 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 1201 } 1202 1203 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "prepareFrame"); 1204 try { 1205 status = onPreDraw(dirty); 1206 } finally { 1207 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 1208 } 1209 saveCount = canvas.save(); 1210 callbacks.onHardwarePreDraw(canvas); 1211 1212 if (mProfileEnabled) { 1213 long now = System.nanoTime(); 1214 float total = (now - getDisplayListStartTime) * 0.000001f; 1215 //noinspection PointlessArithmeticExpression 1216 mProfileData[mProfileCurrentFrame] = total; 1217 } 1218 1219 if (displayList != null) { 1220 long drawDisplayListStartTime = 0; 1221 if (mProfileEnabled) { 1222 drawDisplayListStartTime = System.nanoTime(); 1223 } 1224 1225 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "drawDisplayList"); 1226 try { 1227 status |= canvas.drawDisplayList(displayList, mRedrawClip, 1228 DisplayList.FLAG_CLIP_CHILDREN); 1229 } finally { 1230 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 1231 } 1232 1233 if (mProfileEnabled) { 1234 long now = System.nanoTime(); 1235 float total = (now - drawDisplayListStartTime) * 0.000001f; 1236 mProfileData[mProfileCurrentFrame + 1] = total; 1237 } 1238 1239 handleFunctorStatus(attachInfo, status); 1240 } else { 1241 // Shouldn't reach here 1242 view.draw(canvas); 1243 } 1244 } finally { 1245 callbacks.onHardwarePostDraw(canvas); 1246 canvas.restoreToCount(saveCount); 1247 view.mRecreateDisplayList = false; 1248 1249 mFrameCount++; 1250 1251 if (mDebugDirtyRegions) { 1252 if (mDebugPaint == null) { 1253 mDebugPaint = new Paint(); 1254 mDebugPaint.setColor(0x7fff0000); 1255 } 1256 1257 if (dirty != null && (mFrameCount & 1) == 0) { 1258 canvas.drawRect(dirty, mDebugPaint); 1259 } 1260 } 1261 } 1262 1263 onPostDraw(); 1264 1265 attachInfo.mIgnoreDirtyState = false; 1266 1267 if ((status & DisplayList.STATUS_DREW) == DisplayList.STATUS_DREW) { 1268 long eglSwapBuffersStartTime = 0; 1269 if (mProfileEnabled) { 1270 eglSwapBuffersStartTime = System.nanoTime(); 1271 } 1272 1273 sEgl.eglSwapBuffers(sEglDisplay, mEglSurface); 1274 1275 if (mProfileEnabled) { 1276 long now = System.nanoTime(); 1277 float total = (now - eglSwapBuffersStartTime) * 0.000001f; 1278 mProfileData[mProfileCurrentFrame + 2] = total; 1279 } 1280 1281 checkEglErrors(); 1282 } 1283 1284 if (mProfileEnabled) { 1285 mProfileLock.unlock(); 1286 } 1287 1288 return dirty == null; 1289 } 1290 } 1291 1292 return false; 1293 } 1294 handleFunctorStatus(View.AttachInfo attachInfo, int status)1295 private void handleFunctorStatus(View.AttachInfo attachInfo, int status) { 1296 // If the draw flag is set, functors will be invoked while executing 1297 // the tree of display lists 1298 if ((status & DisplayList.STATUS_DRAW) != 0) { 1299 if (mRedrawClip.isEmpty()) { 1300 attachInfo.mViewRootImpl.invalidate(); 1301 } else { 1302 attachInfo.mViewRootImpl.invalidateChildInParent(null, mRedrawClip); 1303 mRedrawClip.setEmpty(); 1304 } 1305 } 1306 1307 if ((status & DisplayList.STATUS_INVOKE) != 0 || 1308 attachInfo.mHandler.hasCallbacks(mFunctorsRunnable)) { 1309 attachInfo.mHandler.removeCallbacks(mFunctorsRunnable); 1310 mFunctorsRunnable.attachInfo = attachInfo; 1311 attachInfo.mHandler.postDelayed(mFunctorsRunnable, FUNCTOR_PROCESS_DELAY); 1312 } 1313 } 1314 1315 @Override detachFunctor(int functor)1316 void detachFunctor(int functor) { 1317 if (mCanvas != null) { 1318 mCanvas.detachFunctor(functor); 1319 } 1320 } 1321 1322 @Override attachFunctor(View.AttachInfo attachInfo, int functor)1323 boolean attachFunctor(View.AttachInfo attachInfo, int functor) { 1324 if (mCanvas != null) { 1325 mCanvas.attachFunctor(functor); 1326 mFunctorsRunnable.attachInfo = attachInfo; 1327 attachInfo.mHandler.removeCallbacks(mFunctorsRunnable); 1328 attachInfo.mHandler.postDelayed(mFunctorsRunnable, 0); 1329 return true; 1330 } 1331 return false; 1332 } 1333 1334 /** 1335 * Ensures the current EGL context is the one we expect. 1336 * 1337 * @return {@link #SURFACE_STATE_ERROR} if the correct EGL context cannot be made current, 1338 * {@link #SURFACE_STATE_UPDATED} if the EGL context was changed or 1339 * {@link #SURFACE_STATE_SUCCESS} if the EGL context was the correct one 1340 */ checkCurrent()1341 int checkCurrent() { 1342 if (mEglThread != Thread.currentThread()) { 1343 throw new IllegalStateException("Hardware acceleration can only be used with a " + 1344 "single UI thread.\nOriginal thread: " + mEglThread + "\n" + 1345 "Current thread: " + Thread.currentThread()); 1346 } 1347 1348 if (!mEglContext.equals(sEgl.eglGetCurrentContext()) || 1349 !mEglSurface.equals(sEgl.eglGetCurrentSurface(EGL_DRAW))) { 1350 if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, mEglContext)) { 1351 Log.e(LOG_TAG, "eglMakeCurrent failed " + 1352 GLUtils.getEGLErrorString(sEgl.eglGetError())); 1353 fallback(true); 1354 return SURFACE_STATE_ERROR; 1355 } else { 1356 if (mUpdateDirtyRegions) { 1357 enableDirtyRegions(); 1358 mUpdateDirtyRegions = false; 1359 } 1360 return SURFACE_STATE_UPDATED; 1361 } 1362 } 1363 return SURFACE_STATE_SUCCESS; 1364 } 1365 } 1366 1367 /** 1368 * Hardware renderer using OpenGL ES 2.0. 1369 */ 1370 static class Gl20Renderer extends GlRenderer { 1371 private GLES20Canvas mGlCanvas; 1372 1373 private static EGLSurface sPbuffer; 1374 private static final Object[] sPbufferLock = new Object[0]; 1375 1376 static class Gl20RendererEglContext extends ManagedEGLContext { 1377 final Handler mHandler = new Handler(); 1378 Gl20RendererEglContext(EGLContext context)1379 public Gl20RendererEglContext(EGLContext context) { 1380 super(context); 1381 } 1382 1383 @Override onTerminate(final EGLContext eglContext)1384 public void onTerminate(final EGLContext eglContext) { 1385 // Make sure we do this on the correct thread. 1386 if (mHandler.getLooper() != Looper.myLooper()) { 1387 mHandler.post(new Runnable() { 1388 @Override 1389 public void run() { 1390 onTerminate(eglContext); 1391 } 1392 }); 1393 return; 1394 } 1395 1396 synchronized (sEglLock) { 1397 if (sEgl == null) return; 1398 1399 if (EGLImpl.getInitCount(sEglDisplay) == 1) { 1400 usePbufferSurface(eglContext); 1401 GLES20Canvas.terminateCaches(); 1402 1403 sEgl.eglDestroyContext(sEglDisplay, eglContext); 1404 sEglContextStorage.set(null); 1405 sEglContextStorage.remove(); 1406 1407 sEgl.eglDestroySurface(sEglDisplay, sPbuffer); 1408 sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, 1409 EGL_NO_SURFACE, EGL_NO_CONTEXT); 1410 1411 sEgl.eglReleaseThread(); 1412 sEgl.eglTerminate(sEglDisplay); 1413 1414 sEgl = null; 1415 sEglDisplay = null; 1416 sEglConfig = null; 1417 sPbuffer = null; 1418 } 1419 } 1420 } 1421 } 1422 Gl20Renderer(boolean translucent)1423 Gl20Renderer(boolean translucent) { 1424 super(2, translucent); 1425 } 1426 1427 @Override createCanvas()1428 HardwareCanvas createCanvas() { 1429 return mGlCanvas = new GLES20Canvas(mTranslucent); 1430 } 1431 1432 @Override createManagedContext(EGLContext eglContext)1433 ManagedEGLContext createManagedContext(EGLContext eglContext) { 1434 return new Gl20Renderer.Gl20RendererEglContext(mEglContext); 1435 } 1436 1437 @Override getConfig(boolean dirtyRegions)1438 int[] getConfig(boolean dirtyRegions) { 1439 return new int[] { 1440 EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT, 1441 EGL_RED_SIZE, 8, 1442 EGL_GREEN_SIZE, 8, 1443 EGL_BLUE_SIZE, 8, 1444 EGL_ALPHA_SIZE, 8, 1445 EGL_DEPTH_SIZE, 0, 1446 EGL_CONFIG_CAVEAT, EGL_NONE, 1447 // TODO: Find a better way to choose the stencil size 1448 EGL_STENCIL_SIZE, mShowOverdraw ? GLES20Canvas.getStencilSize() : 0, 1449 EGL_SURFACE_TYPE, EGL_WINDOW_BIT | 1450 (dirtyRegions ? EGL14.EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0), 1451 EGL_NONE 1452 }; 1453 } 1454 1455 @Override initCaches()1456 void initCaches() { 1457 GLES20Canvas.initCaches(); 1458 } 1459 1460 @Override canDraw()1461 boolean canDraw() { 1462 return super.canDraw() && mGlCanvas != null; 1463 } 1464 1465 @Override onPreDraw(Rect dirty)1466 int onPreDraw(Rect dirty) { 1467 return mGlCanvas.onPreDraw(dirty); 1468 } 1469 1470 @Override onPostDraw()1471 void onPostDraw() { 1472 mGlCanvas.onPostDraw(); 1473 } 1474 1475 @Override destroy(boolean full)1476 void destroy(boolean full) { 1477 try { 1478 super.destroy(full); 1479 } finally { 1480 if (full && mGlCanvas != null) { 1481 mGlCanvas = null; 1482 } 1483 } 1484 } 1485 1486 @Override setup(int width, int height)1487 void setup(int width, int height) { 1488 super.setup(width, height); 1489 if (mVsyncDisabled) { 1490 disableVsync(); 1491 } 1492 } 1493 1494 @Override pushLayerUpdate(HardwareLayer layer)1495 void pushLayerUpdate(HardwareLayer layer) { 1496 mGlCanvas.pushLayerUpdate(layer); 1497 } 1498 1499 @Override createDisplayList(String name)1500 public DisplayList createDisplayList(String name) { 1501 return new GLES20DisplayList(name); 1502 } 1503 1504 @Override createHardwareLayer(boolean isOpaque)1505 HardwareLayer createHardwareLayer(boolean isOpaque) { 1506 return new GLES20TextureLayer(isOpaque); 1507 } 1508 1509 @Override createHardwareLayer(int width, int height, boolean isOpaque)1510 HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque) { 1511 return new GLES20RenderLayer(width, height, isOpaque); 1512 } 1513 1514 @Override createSurfaceTexture(HardwareLayer layer)1515 SurfaceTexture createSurfaceTexture(HardwareLayer layer) { 1516 return ((GLES20TextureLayer) layer).getSurfaceTexture(); 1517 } 1518 1519 @Override setSurfaceTexture(HardwareLayer layer, SurfaceTexture surfaceTexture)1520 void setSurfaceTexture(HardwareLayer layer, SurfaceTexture surfaceTexture) { 1521 ((GLES20TextureLayer) layer).setSurfaceTexture(surfaceTexture); 1522 } 1523 1524 @Override safelyRun(Runnable action)1525 boolean safelyRun(Runnable action) { 1526 boolean needsContext = true; 1527 if (isEnabled() && checkCurrent() != SURFACE_STATE_ERROR) needsContext = false; 1528 1529 if (needsContext) { 1530 Gl20RendererEglContext managedContext = 1531 (Gl20RendererEglContext) sEglContextStorage.get(); 1532 if (managedContext == null) return false; 1533 usePbufferSurface(managedContext.getContext()); 1534 } 1535 1536 try { 1537 action.run(); 1538 } finally { 1539 if (needsContext) { 1540 sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, 1541 EGL_NO_SURFACE, EGL_NO_CONTEXT); 1542 } 1543 } 1544 1545 return true; 1546 } 1547 1548 @Override destroyLayers(final View view)1549 void destroyLayers(final View view) { 1550 if (view != null) { 1551 safelyRun(new Runnable() { 1552 @Override 1553 public void run() { 1554 if (mCanvas != null) { 1555 mCanvas.clearLayerUpdates(); 1556 } 1557 destroyHardwareLayer(view); 1558 GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS); 1559 } 1560 }); 1561 } 1562 } 1563 destroyHardwareLayer(View view)1564 private static void destroyHardwareLayer(View view) { 1565 view.destroyLayer(true); 1566 1567 if (view instanceof ViewGroup) { 1568 ViewGroup group = (ViewGroup) view; 1569 1570 int count = group.getChildCount(); 1571 for (int i = 0; i < count; i++) { 1572 destroyHardwareLayer(group.getChildAt(i)); 1573 } 1574 } 1575 } 1576 1577 @Override destroyHardwareResources(final View view)1578 void destroyHardwareResources(final View view) { 1579 if (view != null) { 1580 safelyRun(new Runnable() { 1581 @Override 1582 public void run() { 1583 if (mCanvas != null) { 1584 mCanvas.clearLayerUpdates(); 1585 } 1586 destroyResources(view); 1587 GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS); 1588 } 1589 }); 1590 } 1591 } 1592 destroyResources(View view)1593 private static void destroyResources(View view) { 1594 view.destroyHardwareResources(); 1595 1596 if (view instanceof ViewGroup) { 1597 ViewGroup group = (ViewGroup) view; 1598 1599 int count = group.getChildCount(); 1600 for (int i = 0; i < count; i++) { 1601 destroyResources(group.getChildAt(i)); 1602 } 1603 } 1604 } 1605 create(boolean translucent)1606 static HardwareRenderer create(boolean translucent) { 1607 if (GLES20Canvas.isAvailable()) { 1608 return new Gl20Renderer(translucent); 1609 } 1610 return null; 1611 } 1612 startTrimMemory(int level)1613 static void startTrimMemory(int level) { 1614 if (sEgl == null || sEglConfig == null) return; 1615 1616 Gl20RendererEglContext managedContext = 1617 (Gl20RendererEglContext) sEglContextStorage.get(); 1618 // We do not have OpenGL objects 1619 if (managedContext == null) { 1620 return; 1621 } else { 1622 usePbufferSurface(managedContext.getContext()); 1623 } 1624 1625 if (level >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE) { 1626 GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_FULL); 1627 } else if (level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) { 1628 GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_MODERATE); 1629 } 1630 } 1631 endTrimMemory()1632 static void endTrimMemory() { 1633 if (sEgl != null && sEglDisplay != null) { 1634 sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 1635 } 1636 } 1637 usePbufferSurface(EGLContext eglContext)1638 private static void usePbufferSurface(EGLContext eglContext) { 1639 synchronized (sPbufferLock) { 1640 // Create a temporary 1x1 pbuffer so we have a context 1641 // to clear our OpenGL objects 1642 if (sPbuffer == null) { 1643 sPbuffer = sEgl.eglCreatePbufferSurface(sEglDisplay, sEglConfig, new int[] { 1644 EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE 1645 }); 1646 } 1647 } 1648 sEgl.eglMakeCurrent(sEglDisplay, sPbuffer, sPbuffer, eglContext); 1649 } 1650 } 1651 } 1652