1 /* 2 * Copyright (C) 2013 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 android.view; 18 19 import android.content.ComponentCallbacks2; 20 import android.graphics.Color; 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.IBinder; 29 import android.os.Looper; 30 import android.os.RemoteException; 31 import android.os.ServiceManager; 32 import android.os.SystemClock; 33 import android.os.SystemProperties; 34 import android.os.Trace; 35 import android.util.DisplayMetrics; 36 import android.util.Log; 37 import android.view.Surface.OutOfResourcesException; 38 39 import com.google.android.gles_jni.EGLImpl; 40 41 import javax.microedition.khronos.egl.EGL10; 42 import javax.microedition.khronos.egl.EGL11; 43 import javax.microedition.khronos.egl.EGLConfig; 44 import javax.microedition.khronos.egl.EGLContext; 45 import javax.microedition.khronos.egl.EGLDisplay; 46 import javax.microedition.khronos.egl.EGLSurface; 47 import javax.microedition.khronos.opengles.GL; 48 49 import java.io.File; 50 import java.io.PrintWriter; 51 import java.util.concurrent.locks.ReentrantLock; 52 53 import static javax.microedition.khronos.egl.EGL10.*; 54 55 /** 56 * Interface for rendering a view hierarchy using hardware acceleration. 57 * 58 * @hide 59 */ 60 public abstract class HardwareRenderer { 61 static final String LOG_TAG = "HardwareRenderer"; 62 63 /** 64 * Name of the file that holds the shaders cache. 65 */ 66 private static final String CACHE_PATH_SHADERS = "com.android.opengl.shaders_cache"; 67 68 /** 69 * Turn on to only refresh the parts of the screen that need updating. 70 * When turned on the property defined by {@link #RENDER_DIRTY_REGIONS_PROPERTY} 71 * must also have the value "true". 72 */ 73 static final boolean RENDER_DIRTY_REGIONS = true; 74 75 /** 76 * System property used to enable or disable dirty regions invalidation. 77 * This property is only queried if {@link #RENDER_DIRTY_REGIONS} is true. 78 * The default value of this property is assumed to be true. 79 * 80 * Possible values: 81 * "true", to enable partial invalidates 82 * "false", to disable partial invalidates 83 */ 84 static final String RENDER_DIRTY_REGIONS_PROPERTY = "debug.hwui.render_dirty_regions"; 85 86 /** 87 * System property used to enable or disable hardware rendering profiling. 88 * The default value of this property is assumed to be false. 89 * 90 * When profiling is enabled, the adb shell dumpsys gfxinfo command will 91 * output extra information about the time taken to execute by the last 92 * frames. 93 * 94 * Possible values: 95 * "true", to enable profiling 96 * "visual_bars", to enable profiling and visualize the results on screen 97 * "visual_lines", to enable profiling and visualize the results on screen 98 * "false", to disable profiling 99 * 100 * @see #PROFILE_PROPERTY_VISUALIZE_BARS 101 * @see #PROFILE_PROPERTY_VISUALIZE_LINES 102 * 103 * @hide 104 */ 105 public static final String PROFILE_PROPERTY = "debug.hwui.profile"; 106 107 /** 108 * Value for {@link #PROFILE_PROPERTY}. When the property is set to this 109 * value, profiling data will be visualized on screen as a bar chart. 110 * 111 * @hide 112 */ 113 public static final String PROFILE_PROPERTY_VISUALIZE_BARS = "visual_bars"; 114 115 /** 116 * Value for {@link #PROFILE_PROPERTY}. When the property is set to this 117 * value, profiling data will be visualized on screen as a line chart. 118 * 119 * @hide 120 */ 121 public static final String PROFILE_PROPERTY_VISUALIZE_LINES = "visual_lines"; 122 123 /** 124 * System property used to specify the number of frames to be used 125 * when doing hardware rendering profiling. 126 * The default value of this property is #PROFILE_MAX_FRAMES. 127 * 128 * When profiling is enabled, the adb shell dumpsys gfxinfo command will 129 * output extra information about the time taken to execute by the last 130 * frames. 131 * 132 * Possible values: 133 * "60", to set the limit of frames to 60 134 */ 135 static final String PROFILE_MAXFRAMES_PROPERTY = "debug.hwui.profile.maxframes"; 136 137 /** 138 * System property used to debug EGL configuration choice. 139 * 140 * Possible values: 141 * "choice", print the chosen configuration only 142 * "all", print all possible configurations 143 */ 144 static final String PRINT_CONFIG_PROPERTY = "debug.hwui.print_config"; 145 146 /** 147 * Turn on to draw dirty regions every other frame. 148 * 149 * Possible values: 150 * "true", to enable dirty regions debugging 151 * "false", to disable dirty regions debugging 152 * 153 * @hide 154 */ 155 public static final String DEBUG_DIRTY_REGIONS_PROPERTY = "debug.hwui.show_dirty_regions"; 156 157 /** 158 * Turn on to flash hardware layers when they update. 159 * 160 * Possible values: 161 * "true", to enable hardware layers updates debugging 162 * "false", to disable hardware layers updates debugging 163 * 164 * @hide 165 */ 166 public static final String DEBUG_SHOW_LAYERS_UPDATES_PROPERTY = 167 "debug.hwui.show_layers_updates"; 168 169 /** 170 * Controls overdraw debugging. 171 * 172 * Possible values: 173 * "false", to disable overdraw debugging 174 * "show", to show overdraw areas on screen 175 * "count", to display an overdraw counter 176 * 177 * @hide 178 */ 179 public static final String DEBUG_OVERDRAW_PROPERTY = "debug.hwui.overdraw"; 180 181 /** 182 * Value for {@link #DEBUG_OVERDRAW_PROPERTY}. When the property is set to this 183 * value, overdraw will be shown on screen by coloring pixels. 184 * 185 * @hide 186 */ 187 public static final String OVERDRAW_PROPERTY_SHOW = "show"; 188 189 /** 190 * Value for {@link #DEBUG_OVERDRAW_PROPERTY}. When the property is set to this 191 * value, an overdraw counter will be shown on screen. 192 * 193 * @hide 194 */ 195 public static final String OVERDRAW_PROPERTY_COUNT = "count"; 196 197 /** 198 * Turn on to debug non-rectangular clip operations. 199 * 200 * Possible values: 201 * "hide", to disable this debug mode 202 * "highlight", highlight drawing commands tested against a non-rectangular clip 203 * "stencil", renders the clip region on screen when set 204 * 205 * @hide 206 */ 207 public static final String DEBUG_SHOW_NON_RECTANGULAR_CLIP_PROPERTY = 208 "debug.hwui.show_non_rect_clip"; 209 210 /** 211 * A process can set this flag to false to prevent the use of hardware 212 * rendering. 213 * 214 * @hide 215 */ 216 public static boolean sRendererDisabled = false; 217 218 /** 219 * Further hardware renderer disabling for the system process. 220 * 221 * @hide 222 */ 223 public static boolean sSystemRendererDisabled = false; 224 225 /** 226 * Number of frames to profile. 227 */ 228 private static final int PROFILE_MAX_FRAMES = 128; 229 230 /** 231 * Number of floats per profiled frame. 232 */ 233 private static final int PROFILE_FRAME_DATA_COUNT = 3; 234 235 private boolean mEnabled; 236 private boolean mRequested = true; 237 238 /** 239 * Invoke this method to disable hardware rendering in the current process. 240 * 241 * @hide 242 */ 243 public static void disable(boolean system) { 244 sRendererDisabled = true; 245 if (system) { 246 sSystemRendererDisabled = true; 247 } 248 } 249 250 /** 251 * Indicates whether hardware acceleration is available under any form for 252 * the view hierarchy. 253 * 254 * @return True if the view hierarchy can potentially be hardware accelerated, 255 * false otherwise 256 */ 257 public static boolean isAvailable() { 258 return GLES20Canvas.isAvailable(); 259 } 260 261 /** 262 * Destroys the hardware rendering context. 263 * 264 * @param full If true, destroys all associated resources. 265 */ 266 abstract void destroy(boolean full); 267 268 /** 269 * Initializes the hardware renderer for the specified surface. 270 * 271 * @param surface The surface to hardware accelerate 272 * 273 * @return True if the initialization was successful, false otherwise. 274 */ 275 abstract boolean initialize(Surface surface) throws OutOfResourcesException; 276 277 /** 278 * Updates the hardware renderer for the specified surface. 279 * 280 * @param surface The surface to hardware accelerate 281 */ 282 abstract void updateSurface(Surface surface) throws OutOfResourcesException; 283 284 /** 285 * Destroys the layers used by the specified view hierarchy. 286 * 287 * @param view The root of the view hierarchy 288 */ 289 abstract void destroyLayers(View view); 290 291 /** 292 * Destroys all hardware rendering resources associated with the specified 293 * view hierarchy. 294 * 295 * @param view The root of the view hierarchy 296 */ 297 abstract void destroyHardwareResources(View view); 298 299 /** 300 * This method should be invoked whenever the current hardware renderer 301 * context should be reset. 302 * 303 * @param surface The surface to hardware accelerate 304 */ 305 abstract void invalidate(Surface surface); 306 307 /** 308 * This method should be invoked to ensure the hardware renderer is in 309 * valid state (for instance, to ensure the correct EGL context is bound 310 * to the current thread.) 311 * 312 * @return true if the renderer is now valid, false otherwise 313 */ 314 abstract boolean validate(); 315 316 /** 317 * This method ensures the hardware renderer is in a valid state 318 * before executing the specified action. 319 * 320 * This method will attempt to set a valid state even if the window 321 * the renderer is attached to was destroyed. 322 * 323 * @return true if the action was run 324 */ 325 abstract boolean safelyRun(Runnable action); 326 327 /** 328 * Setup the hardware renderer for drawing. This is called whenever the 329 * size of the target surface changes or when the surface is first created. 330 * 331 * @param width Width of the drawing surface. 332 * @param height Height of the drawing surface. 333 */ 334 abstract void setup(int width, int height); 335 336 /** 337 * Gets the current width of the surface. This is the width that the surface 338 * was last set to in a call to {@link #setup(int, int)}. 339 * 340 * @return the current width of the surface 341 */ 342 abstract int getWidth(); 343 344 /** 345 * Gets the current height of the surface. This is the height that the surface 346 * was last set to in a call to {@link #setup(int, int)}. 347 * 348 * @return the current width of the surface 349 */ 350 abstract int getHeight(); 351 352 /** 353 * Gets the current canvas associated with this HardwareRenderer. 354 * 355 * @return the current HardwareCanvas 356 */ 357 abstract HardwareCanvas getCanvas(); 358 359 /** 360 * Outputs extra debugging information in the specified file descriptor. 361 * @param pw 362 */ 363 abstract void dumpGfxInfo(PrintWriter pw); 364 365 /** 366 * Outputs the total number of frames rendered (used for fps calculations) 367 * 368 * @return the number of frames rendered 369 */ 370 abstract long getFrameCount(); 371 372 /** 373 * Loads system properties used by the renderer. This method is invoked 374 * whenever system properties are modified. Implementations can use this 375 * to trigger live updates of the renderer based on properties. 376 * 377 * @param surface The surface to update with the new properties. 378 * Can be null. 379 * 380 * @return True if a property has changed. 381 */ 382 abstract boolean loadSystemProperties(Surface surface); 383 384 private static native boolean nLoadProperties(); 385 386 /** 387 * Sets the directory to use as a persistent storage for hardware rendering 388 * resources. 389 * 390 * @param cacheDir A directory the current process can write to 391 * 392 * @hide 393 */ 394 public static void setupDiskCache(File cacheDir) { 395 nSetupShadersDiskCache(new File(cacheDir, CACHE_PATH_SHADERS).getAbsolutePath()); 396 } 397 398 private static native void nSetupShadersDiskCache(String cacheFile); 399 400 /** 401 * Notifies EGL that the frame is about to be rendered. 402 * @param size 403 */ 404 static void beginFrame(int[] size) { 405 nBeginFrame(size); 406 } 407 408 private static native void nBeginFrame(int[] size); 409 410 /** 411 * Returns the current system time according to the renderer. 412 * This method is used for debugging only and should not be used 413 * as a clock. 414 */ 415 static long getSystemTime() { 416 return nGetSystemTime(); 417 } 418 419 private static native long nGetSystemTime(); 420 421 /** 422 * Preserves the back buffer of the current surface after a buffer swap. 423 * Calling this method sets the EGL_SWAP_BEHAVIOR attribute of the current 424 * surface to EGL_BUFFER_PRESERVED. Calling this method requires an EGL 425 * config that supports EGL_SWAP_BEHAVIOR_PRESERVED_BIT. 426 * 427 * @return True if the swap behavior was successfully changed, 428 * false otherwise. 429 */ 430 static boolean preserveBackBuffer() { 431 return nPreserveBackBuffer(); 432 } 433 434 private static native boolean nPreserveBackBuffer(); 435 436 /** 437 * Indicates whether the current surface preserves its back buffer 438 * after a buffer swap. 439 * 440 * @return True, if the surface's EGL_SWAP_BEHAVIOR is EGL_BUFFER_PRESERVED, 441 * false otherwise 442 */ 443 static boolean isBackBufferPreserved() { 444 return nIsBackBufferPreserved(); 445 } 446 447 private static native boolean nIsBackBufferPreserved(); 448 449 /** 450 * Indicates that the specified hardware layer needs to be updated 451 * as soon as possible. 452 * 453 * @param layer The hardware layer that needs an update 454 * 455 * @see #flushLayerUpdates() 456 * @see #cancelLayerUpdate(HardwareLayer) 457 */ 458 abstract void pushLayerUpdate(HardwareLayer layer); 459 460 /** 461 * Cancels a queued layer update. If the specified layer was not 462 * queued for update, this method has no effect. 463 * 464 * @param layer The layer whose update to cancel 465 * 466 * @see #pushLayerUpdate(HardwareLayer) 467 */ 468 abstract void cancelLayerUpdate(HardwareLayer layer); 469 470 /** 471 * Forces all enqueued layer updates to be executed immediately. 472 * 473 * @see #pushLayerUpdate(HardwareLayer) 474 */ 475 abstract void flushLayerUpdates(); 476 477 /** 478 * Interface used to receive callbacks whenever a view is drawn by 479 * a hardware renderer instance. 480 */ 481 interface HardwareDrawCallbacks { 482 /** 483 * Invoked before a view is drawn by a hardware renderer. 484 * This method can be used to apply transformations to the 485 * canvas but no drawing command should be issued. 486 * 487 * @param canvas The Canvas used to render the view. 488 */ 489 void onHardwarePreDraw(HardwareCanvas canvas); 490 491 /** 492 * Invoked after a view is drawn by a hardware renderer. 493 * It is safe to invoke drawing commands from this method. 494 * 495 * @param canvas The Canvas used to render the view. 496 */ 497 void onHardwarePostDraw(HardwareCanvas canvas); 498 } 499 500 /** 501 * Draws the specified view. 502 * 503 * @param view The view to draw. 504 * @param attachInfo AttachInfo tied to the specified view. 505 * @param callbacks Callbacks invoked when drawing happens. 506 * @param dirty The dirty rectangle to update, can be null. 507 */ 508 abstract void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks, 509 Rect dirty); 510 511 /** 512 * Creates a new display list that can be used to record batches of 513 * drawing operations. 514 * 515 * @param name The name of the display list, used for debugging purpose. May be null. 516 * 517 * @return A new display list. 518 * 519 * @hide 520 */ 521 public abstract DisplayList createDisplayList(String name); 522 523 /** 524 * Creates a new hardware layer. A hardware layer built by calling this 525 * method will be treated as a texture layer, instead of as a render target. 526 * 527 * @param isOpaque Whether the layer should be opaque or not 528 * 529 * @return A hardware layer 530 */ 531 abstract HardwareLayer createHardwareLayer(boolean isOpaque); 532 533 /** 534 * Creates a new hardware layer. 535 * 536 * @param width The minimum width of the layer 537 * @param height The minimum height of the layer 538 * @param isOpaque Whether the layer should be opaque or not 539 * 540 * @return A hardware layer 541 */ 542 abstract HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque); 543 544 /** 545 * Creates a new {@link SurfaceTexture} that can be used to render into the 546 * specified hardware layer. 547 * 548 * @param layer The layer to render into using a {@link android.graphics.SurfaceTexture} 549 * 550 * @return A {@link SurfaceTexture} 551 */ 552 abstract SurfaceTexture createSurfaceTexture(HardwareLayer layer); 553 554 /** 555 * Sets the {@link android.graphics.SurfaceTexture} that will be used to 556 * render into the specified hardware layer. 557 * 558 * @param layer The layer to render into using a {@link android.graphics.SurfaceTexture} 559 * @param surfaceTexture The {@link android.graphics.SurfaceTexture} to use for the layer 560 */ 561 abstract void setSurfaceTexture(HardwareLayer layer, SurfaceTexture surfaceTexture); 562 563 /** 564 * Detaches the specified functor from the current functor execution queue. 565 * 566 * @param functor The native functor to remove from the execution queue. 567 * 568 * @see HardwareCanvas#callDrawGLFunction(int) 569 * @see #attachFunctor(android.view.View.AttachInfo, int) 570 */ 571 abstract void detachFunctor(int functor); 572 573 /** 574 * Schedules the specified functor in the functors execution queue. 575 * 576 * @param attachInfo AttachInfo tied to this renderer. 577 * @param functor The native functor to insert in the execution queue. 578 * 579 * @see HardwareCanvas#callDrawGLFunction(int) 580 * @see #detachFunctor(int) 581 * 582 * @return true if the functor was attached successfully 583 */ 584 abstract boolean attachFunctor(View.AttachInfo attachInfo, int functor); 585 586 /** 587 * Initializes the hardware renderer for the specified surface and setup the 588 * renderer for drawing, if needed. This is invoked when the ViewAncestor has 589 * potentially lost the hardware renderer. The hardware renderer should be 590 * reinitialized and setup when the render {@link #isRequested()} and 591 * {@link #isEnabled()}. 592 * 593 * @param width The width of the drawing surface. 594 * @param height The height of the drawing surface. 595 * @param surface The surface to hardware accelerate 596 * 597 * @return true if the surface was initialized, false otherwise. Returning 598 * false might mean that the surface was already initialized. 599 */ 600 boolean initializeIfNeeded(int width, int height, Surface surface) 601 throws OutOfResourcesException { 602 if (isRequested()) { 603 // We lost the gl context, so recreate it. 604 if (!isEnabled()) { 605 if (initialize(surface)) { 606 setup(width, height); 607 return true; 608 } 609 } 610 } 611 return false; 612 } 613 614 /** 615 * Optional, sets the name of the renderer. Useful for debugging purposes. 616 * 617 * @param name The name of this renderer, can be null 618 */ 619 abstract void setName(String name); 620 621 /** 622 * Creates a hardware renderer using OpenGL. 623 * 624 * @param glVersion The version of OpenGL to use (1 for OpenGL 1, 11 for OpenGL 1.1, etc.) 625 * @param translucent True if the surface is translucent, false otherwise 626 * 627 * @return A hardware renderer backed by OpenGL. 628 */ 629 static HardwareRenderer createGlRenderer(int glVersion, boolean translucent) { 630 switch (glVersion) { 631 case 2: 632 return Gl20Renderer.create(translucent); 633 } 634 throw new IllegalArgumentException("Unknown GL version: " + glVersion); 635 } 636 637 /** 638 * Invoke this method when the system is running out of memory. This 639 * method will attempt to recover as much memory as possible, based on 640 * the specified hint. 641 * 642 * @param level Hint about the amount of memory that should be trimmed, 643 * see {@link android.content.ComponentCallbacks} 644 */ 645 static void trimMemory(int level) { 646 startTrimMemory(level); 647 endTrimMemory(); 648 } 649 650 /** 651 * Starts the process of trimming memory. Usually this call will setup 652 * hardware rendering context and reclaim memory.Extra cleanup might 653 * be required by calling {@link #endTrimMemory()}. 654 * 655 * @param level Hint about the amount of memory that should be trimmed, 656 * see {@link android.content.ComponentCallbacks} 657 */ 658 static void startTrimMemory(int level) { 659 Gl20Renderer.startTrimMemory(level); 660 } 661 662 /** 663 * Finishes the process of trimming memory. This method will usually 664 * cleanup special resources used by the memory trimming process. 665 */ 666 static void endTrimMemory() { 667 Gl20Renderer.endTrimMemory(); 668 } 669 670 /** 671 * Indicates whether hardware acceleration is currently enabled. 672 * 673 * @return True if hardware acceleration is in use, false otherwise. 674 */ 675 boolean isEnabled() { 676 return mEnabled; 677 } 678 679 /** 680 * Indicates whether hardware acceleration is currently enabled. 681 * 682 * @param enabled True if the hardware renderer is in use, false otherwise. 683 */ 684 void setEnabled(boolean enabled) { 685 mEnabled = enabled; 686 } 687 688 /** 689 * Indicates whether hardware acceleration is currently request but not 690 * necessarily enabled yet. 691 * 692 * @return True if requested, false otherwise. 693 */ 694 boolean isRequested() { 695 return mRequested; 696 } 697 698 /** 699 * Indicates whether hardware acceleration is currently requested but not 700 * necessarily enabled yet. 701 * 702 * @return True to request hardware acceleration, false otherwise. 703 */ 704 void setRequested(boolean requested) { 705 mRequested = requested; 706 } 707 708 /** 709 * Describes a series of frames that should be drawn on screen as a graph. 710 * Each frame is composed of 1 or more elements. 711 */ 712 abstract class GraphDataProvider { 713 /** 714 * Draws the graph as bars. Frame elements are stacked on top of 715 * each other. 716 */ 717 public static final int GRAPH_TYPE_BARS = 0; 718 /** 719 * Draws the graph as lines. The number of series drawn corresponds 720 * to the number of elements. 721 */ 722 public static final int GRAPH_TYPE_LINES = 1; 723 724 /** 725 * Returns the type of graph to render. 726 * 727 * @return {@link #GRAPH_TYPE_BARS} or {@link #GRAPH_TYPE_LINES} 728 */ 729 abstract int getGraphType(); 730 731 /** 732 * This method is invoked before the graph is drawn. This method 733 * can be used to compute sizes, etc. 734 * 735 * @param metrics The display metrics 736 */ 737 abstract void prepare(DisplayMetrics metrics); 738 739 /** 740 * @return The size in pixels of a vertical unit. 741 */ 742 abstract int getVerticalUnitSize(); 743 744 /** 745 * @return The size in pixels of a horizontal unit. 746 */ 747 abstract int getHorizontalUnitSize(); 748 749 /** 750 * @return The size in pixels of the margin between horizontal units. 751 */ 752 abstract int getHorizontaUnitMargin(); 753 754 /** 755 * An optional threshold value. 756 * 757 * @return A value >= 0 to draw the threshold, a negative value 758 * to ignore it. 759 */ 760 abstract float getThreshold(); 761 762 /** 763 * The data to draw in the graph. The number of elements in the 764 * array must be at least {@link #getFrameCount()} * {@link #getElementCount()}. 765 * If a value is negative the following values will be ignored. 766 */ 767 abstract float[] getData(); 768 769 /** 770 * Returns the number of frames to render in the graph. 771 */ 772 abstract int getFrameCount(); 773 774 /** 775 * Returns the number of elements in each frame. This directly affects 776 * the number of series drawn in the graph. 777 */ 778 abstract int getElementCount(); 779 780 /** 781 * Returns the current frame, if any. If the returned value is negative 782 * the current frame is ignored. 783 */ 784 abstract int getCurrentFrame(); 785 786 /** 787 * Prepares the paint to draw the specified element (or series.) 788 */ 789 abstract void setupGraphPaint(Paint paint, int elementIndex); 790 791 /** 792 * Prepares the paint to draw the threshold. 793 */ 794 abstract void setupThresholdPaint(Paint paint); 795 796 /** 797 * Prepares the paint to draw the current frame indicator. 798 */ 799 abstract void setupCurrentFramePaint(Paint paint); 800 } 801 802 @SuppressWarnings({"deprecation"}) 803 static abstract class GlRenderer extends HardwareRenderer { 804 static final int SURFACE_STATE_ERROR = 0; 805 static final int SURFACE_STATE_SUCCESS = 1; 806 static final int SURFACE_STATE_UPDATED = 2; 807 808 static final int FUNCTOR_PROCESS_DELAY = 4; 809 810 private static final int PROFILE_DRAW_MARGIN = 0; 811 private static final int PROFILE_DRAW_WIDTH = 3; 812 private static final int[] PROFILE_DRAW_COLORS = { 0xcf3e66cc, 0xcfdc3912, 0xcfe69800 }; 813 private static final int PROFILE_DRAW_CURRENT_FRAME_COLOR = 0xcf5faa4d; 814 private static final int PROFILE_DRAW_THRESHOLD_COLOR = 0xff5faa4d; 815 private static final int PROFILE_DRAW_THRESHOLD_STROKE_WIDTH = 2; 816 private static final int PROFILE_DRAW_DP_PER_MS = 7; 817 818 private static final String[] VISUALIZERS = { 819 PROFILE_PROPERTY_VISUALIZE_BARS, 820 PROFILE_PROPERTY_VISUALIZE_LINES 821 }; 822 823 private static final String[] OVERDRAW = { 824 OVERDRAW_PROPERTY_SHOW, 825 OVERDRAW_PROPERTY_COUNT 826 }; 827 private static final int OVERDRAW_TYPE_COUNT = 1; 828 829 static EGL10 sEgl; 830 static EGLDisplay sEglDisplay; 831 static EGLConfig sEglConfig; 832 static final Object[] sEglLock = new Object[0]; 833 int mWidth = -1, mHeight = -1; 834 835 static final ThreadLocal<ManagedEGLContext> sEglContextStorage 836 = new ThreadLocal<ManagedEGLContext>(); 837 838 EGLContext mEglContext; 839 Thread mEglThread; 840 841 EGLSurface mEglSurface; 842 843 GL mGl; 844 HardwareCanvas mCanvas; 845 846 String mName; 847 848 long mFrameCount; 849 Paint mDebugPaint; 850 851 static boolean sDirtyRegions; 852 static final boolean sDirtyRegionsRequested; 853 static { 854 String dirtyProperty = SystemProperties.get(RENDER_DIRTY_REGIONS_PROPERTY, "true"); 855 //noinspection PointlessBooleanExpression,ConstantConditions 856 sDirtyRegions = RENDER_DIRTY_REGIONS && "true".equalsIgnoreCase(dirtyProperty); 857 sDirtyRegionsRequested = sDirtyRegions; 858 } 859 860 boolean mDirtyRegionsEnabled; 861 boolean mUpdateDirtyRegions; 862 863 boolean mProfileEnabled; 864 int mProfileVisualizerType = -1; 865 float[] mProfileData; 866 ReentrantLock mProfileLock; 867 int mProfileCurrentFrame = -PROFILE_FRAME_DATA_COUNT; 868 869 GraphDataProvider mDebugDataProvider; 870 float[][] mProfileShapes; 871 Paint mProfilePaint; 872 873 boolean mDebugDirtyRegions; 874 int mDebugOverdraw = -1; 875 HardwareLayer mDebugOverdrawLayer; 876 Paint mDebugOverdrawPaint; 877 878 final int mGlVersion; 879 final boolean mTranslucent; 880 881 private boolean mDestroyed; 882 883 private final Rect mRedrawClip = new Rect(); 884 885 private final int[] mSurfaceSize = new int[2]; 886 private final FunctorsRunnable mFunctorsRunnable = new FunctorsRunnable(); 887 888 private long mDrawDelta = Long.MAX_VALUE; 889 890 GlRenderer(int glVersion, boolean translucent) { 891 mGlVersion = glVersion; 892 mTranslucent = translucent; 893 894 loadSystemProperties(null); 895 } 896 897 @Override 898 boolean loadSystemProperties(Surface surface) { 899 boolean value; 900 boolean changed = false; 901 902 String profiling = SystemProperties.get(PROFILE_PROPERTY); 903 int graphType = search(VISUALIZERS, profiling); 904 value = graphType >= 0; 905 906 if (graphType != mProfileVisualizerType) { 907 changed = true; 908 mProfileVisualizerType = graphType; 909 910 mProfileShapes = null; 911 mProfilePaint = null; 912 913 if (value) { 914 mDebugDataProvider = new DrawPerformanceDataProvider(graphType); 915 } else { 916 mDebugDataProvider = null; 917 } 918 } 919 920 // If on-screen profiling is not enabled, we need to check whether 921 // console profiling only is enabled 922 if (!value) { 923 value = Boolean.parseBoolean(profiling); 924 } 925 926 if (value != mProfileEnabled) { 927 changed = true; 928 mProfileEnabled = value; 929 930 if (mProfileEnabled) { 931 Log.d(LOG_TAG, "Profiling hardware renderer"); 932 933 int maxProfileFrames = SystemProperties.getInt(PROFILE_MAXFRAMES_PROPERTY, 934 PROFILE_MAX_FRAMES); 935 mProfileData = new float[maxProfileFrames * PROFILE_FRAME_DATA_COUNT]; 936 for (int i = 0; i < mProfileData.length; i += PROFILE_FRAME_DATA_COUNT) { 937 mProfileData[i] = mProfileData[i + 1] = mProfileData[i + 2] = -1; 938 } 939 940 mProfileLock = new ReentrantLock(); 941 } else { 942 mProfileData = null; 943 mProfileLock = null; 944 mProfileVisualizerType = -1; 945 } 946 947 mProfileCurrentFrame = -PROFILE_FRAME_DATA_COUNT; 948 } 949 950 value = SystemProperties.getBoolean(DEBUG_DIRTY_REGIONS_PROPERTY, false); 951 if (value != mDebugDirtyRegions) { 952 changed = true; 953 mDebugDirtyRegions = value; 954 955 if (mDebugDirtyRegions) { 956 Log.d(LOG_TAG, "Debugging dirty regions"); 957 } 958 } 959 960 String overdraw = SystemProperties.get(HardwareRenderer.DEBUG_OVERDRAW_PROPERTY); 961 int debugOverdraw = search(OVERDRAW, overdraw); 962 if (debugOverdraw != mDebugOverdraw) { 963 changed = true; 964 mDebugOverdraw = debugOverdraw; 965 966 if (mDebugOverdraw != OVERDRAW_TYPE_COUNT) { 967 if (mDebugOverdrawLayer != null) { 968 mDebugOverdrawLayer.destroy(); 969 mDebugOverdrawLayer = null; 970 mDebugOverdrawPaint = null; 971 } 972 } 973 } 974 975 if (nLoadProperties()) { 976 changed = true; 977 } 978 979 return changed; 980 } 981 982 private static int search(String[] values, String value) { 983 for (int i = 0; i < values.length; i++) { 984 if (values[i].equals(value)) return i; 985 } 986 return -1; 987 } 988 989 @Override 990 void dumpGfxInfo(PrintWriter pw) { 991 if (mProfileEnabled) { 992 pw.printf("\n\tDraw\tProcess\tExecute\n"); 993 994 mProfileLock.lock(); 995 try { 996 for (int i = 0; i < mProfileData.length; i += PROFILE_FRAME_DATA_COUNT) { 997 if (mProfileData[i] < 0) { 998 break; 999 } 1000 pw.printf("\t%3.2f\t%3.2f\t%3.2f\n", mProfileData[i], mProfileData[i + 1], 1001 mProfileData[i + 2]); 1002 mProfileData[i] = mProfileData[i + 1] = mProfileData[i + 2] = -1; 1003 } 1004 mProfileCurrentFrame = mProfileData.length; 1005 } finally { 1006 mProfileLock.unlock(); 1007 } 1008 } 1009 } 1010 1011 @Override 1012 long getFrameCount() { 1013 return mFrameCount; 1014 } 1015 1016 /** 1017 * Indicates whether this renderer instance can track and update dirty regions. 1018 */ 1019 boolean hasDirtyRegions() { 1020 return mDirtyRegionsEnabled; 1021 } 1022 1023 /** 1024 * Checks for OpenGL errors. If an error has occured, {@link #destroy(boolean)} 1025 * is invoked and the requested flag is turned off. The error code is 1026 * also logged as a warning. 1027 */ 1028 void checkEglErrors() { 1029 if (isEnabled()) { 1030 checkEglErrorsForced(); 1031 } 1032 } 1033 1034 private void checkEglErrorsForced() { 1035 int error = sEgl.eglGetError(); 1036 if (error != EGL_SUCCESS) { 1037 // something bad has happened revert to 1038 // normal rendering. 1039 Log.w(LOG_TAG, "EGL error: " + GLUtils.getEGLErrorString(error)); 1040 fallback(error != EGL11.EGL_CONTEXT_LOST); 1041 } 1042 } 1043 1044 private void fallback(boolean fallback) { 1045 destroy(true); 1046 if (fallback) { 1047 // we'll try again if it was context lost 1048 setRequested(false); 1049 Log.w(LOG_TAG, "Mountain View, we've had a problem here. " 1050 + "Switching back to software rendering."); 1051 } 1052 } 1053 1054 @Override 1055 boolean initialize(Surface surface) throws OutOfResourcesException { 1056 if (isRequested() && !isEnabled()) { 1057 boolean contextCreated = initializeEgl(); 1058 mGl = createEglSurface(surface); 1059 mDestroyed = false; 1060 1061 if (mGl != null) { 1062 int err = sEgl.eglGetError(); 1063 if (err != EGL_SUCCESS) { 1064 destroy(true); 1065 setRequested(false); 1066 } else { 1067 if (mCanvas == null) { 1068 mCanvas = createCanvas(); 1069 mCanvas.setName(mName); 1070 } 1071 setEnabled(true); 1072 1073 if (contextCreated) { 1074 initAtlas(); 1075 } 1076 } 1077 1078 return mCanvas != null; 1079 } 1080 } 1081 return false; 1082 } 1083 1084 @Override 1085 void updateSurface(Surface surface) throws OutOfResourcesException { 1086 if (isRequested() && isEnabled()) { 1087 createEglSurface(surface); 1088 } 1089 } 1090 1091 abstract HardwareCanvas createCanvas(); 1092 1093 abstract int[] getConfig(boolean dirtyRegions); 1094 1095 boolean initializeEgl() { 1096 synchronized (sEglLock) { 1097 if (sEgl == null && sEglConfig == null) { 1098 sEgl = (EGL10) EGLContext.getEGL(); 1099 1100 // Get to the default display. 1101 sEglDisplay = sEgl.eglGetDisplay(EGL_DEFAULT_DISPLAY); 1102 1103 if (sEglDisplay == EGL_NO_DISPLAY) { 1104 throw new RuntimeException("eglGetDisplay failed " 1105 + GLUtils.getEGLErrorString(sEgl.eglGetError())); 1106 } 1107 1108 // We can now initialize EGL for that display 1109 int[] version = new int[2]; 1110 if (!sEgl.eglInitialize(sEglDisplay, version)) { 1111 throw new RuntimeException("eglInitialize failed " + 1112 GLUtils.getEGLErrorString(sEgl.eglGetError())); 1113 } 1114 1115 checkEglErrorsForced(); 1116 1117 sEglConfig = loadEglConfig(); 1118 } 1119 } 1120 1121 ManagedEGLContext managedContext = sEglContextStorage.get(); 1122 mEglContext = managedContext != null ? managedContext.getContext() : null; 1123 mEglThread = Thread.currentThread(); 1124 1125 if (mEglContext == null) { 1126 mEglContext = createContext(sEgl, sEglDisplay, sEglConfig); 1127 sEglContextStorage.set(createManagedContext(mEglContext)); 1128 return true; 1129 } 1130 1131 return false; 1132 } 1133 1134 private EGLConfig loadEglConfig() { 1135 EGLConfig eglConfig = chooseEglConfig(); 1136 if (eglConfig == null) { 1137 // We tried to use EGL_SWAP_BEHAVIOR_PRESERVED_BIT, try again without 1138 if (sDirtyRegions) { 1139 sDirtyRegions = false; 1140 eglConfig = chooseEglConfig(); 1141 if (eglConfig == null) { 1142 throw new RuntimeException("eglConfig not initialized"); 1143 } 1144 } else { 1145 throw new RuntimeException("eglConfig not initialized"); 1146 } 1147 } 1148 return eglConfig; 1149 } 1150 1151 abstract ManagedEGLContext createManagedContext(EGLContext eglContext); 1152 1153 private EGLConfig chooseEglConfig() { 1154 EGLConfig[] configs = new EGLConfig[1]; 1155 int[] configsCount = new int[1]; 1156 int[] configSpec = getConfig(sDirtyRegions); 1157 1158 // Debug 1159 final String debug = SystemProperties.get(PRINT_CONFIG_PROPERTY, ""); 1160 if ("all".equalsIgnoreCase(debug)) { 1161 sEgl.eglChooseConfig(sEglDisplay, configSpec, null, 0, configsCount); 1162 1163 EGLConfig[] debugConfigs = new EGLConfig[configsCount[0]]; 1164 sEgl.eglChooseConfig(sEglDisplay, configSpec, debugConfigs, 1165 configsCount[0], configsCount); 1166 1167 for (EGLConfig config : debugConfigs) { 1168 printConfig(config); 1169 } 1170 } 1171 1172 if (!sEgl.eglChooseConfig(sEglDisplay, configSpec, configs, 1, configsCount)) { 1173 throw new IllegalArgumentException("eglChooseConfig failed " + 1174 GLUtils.getEGLErrorString(sEgl.eglGetError())); 1175 } else if (configsCount[0] > 0) { 1176 if ("choice".equalsIgnoreCase(debug)) { 1177 printConfig(configs[0]); 1178 } 1179 return configs[0]; 1180 } 1181 1182 return null; 1183 } 1184 1185 private static void printConfig(EGLConfig config) { 1186 int[] value = new int[1]; 1187 1188 Log.d(LOG_TAG, "EGL configuration " + config + ":"); 1189 1190 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_RED_SIZE, value); 1191 Log.d(LOG_TAG, " RED_SIZE = " + value[0]); 1192 1193 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_GREEN_SIZE, value); 1194 Log.d(LOG_TAG, " GREEN_SIZE = " + value[0]); 1195 1196 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_BLUE_SIZE, value); 1197 Log.d(LOG_TAG, " BLUE_SIZE = " + value[0]); 1198 1199 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_ALPHA_SIZE, value); 1200 Log.d(LOG_TAG, " ALPHA_SIZE = " + value[0]); 1201 1202 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_DEPTH_SIZE, value); 1203 Log.d(LOG_TAG, " DEPTH_SIZE = " + value[0]); 1204 1205 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_STENCIL_SIZE, value); 1206 Log.d(LOG_TAG, " STENCIL_SIZE = " + value[0]); 1207 1208 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_SAMPLE_BUFFERS, value); 1209 Log.d(LOG_TAG, " SAMPLE_BUFFERS = " + value[0]); 1210 1211 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_SAMPLES, value); 1212 Log.d(LOG_TAG, " SAMPLES = " + value[0]); 1213 1214 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_SURFACE_TYPE, value); 1215 Log.d(LOG_TAG, " SURFACE_TYPE = 0x" + Integer.toHexString(value[0])); 1216 1217 sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_CONFIG_CAVEAT, value); 1218 Log.d(LOG_TAG, " CONFIG_CAVEAT = 0x" + Integer.toHexString(value[0])); 1219 } 1220 1221 GL createEglSurface(Surface surface) throws OutOfResourcesException { 1222 // Check preconditions. 1223 if (sEgl == null) { 1224 throw new RuntimeException("egl not initialized"); 1225 } 1226 if (sEglDisplay == null) { 1227 throw new RuntimeException("eglDisplay not initialized"); 1228 } 1229 if (sEglConfig == null) { 1230 throw new RuntimeException("eglConfig not initialized"); 1231 } 1232 if (Thread.currentThread() != mEglThread) { 1233 throw new IllegalStateException("HardwareRenderer cannot be used " 1234 + "from multiple threads"); 1235 } 1236 1237 // In case we need to destroy an existing surface 1238 destroySurface(); 1239 1240 // Create an EGL surface we can render into. 1241 if (!createSurface(surface)) { 1242 return null; 1243 } 1244 1245 initCaches(); 1246 1247 return mEglContext.getGL(); 1248 } 1249 1250 private void enableDirtyRegions() { 1251 // If mDirtyRegions is set, this means we have an EGL configuration 1252 // with EGL_SWAP_BEHAVIOR_PRESERVED_BIT set 1253 if (sDirtyRegions) { 1254 if (!(mDirtyRegionsEnabled = preserveBackBuffer())) { 1255 Log.w(LOG_TAG, "Backbuffer cannot be preserved"); 1256 } 1257 } else if (sDirtyRegionsRequested) { 1258 // If mDirtyRegions is not set, our EGL configuration does not 1259 // have EGL_SWAP_BEHAVIOR_PRESERVED_BIT; however, the default 1260 // swap behavior might be EGL_BUFFER_PRESERVED, which means we 1261 // want to set mDirtyRegions. We try to do this only if dirty 1262 // regions were initially requested as part of the device 1263 // configuration (see RENDER_DIRTY_REGIONS) 1264 mDirtyRegionsEnabled = isBackBufferPreserved(); 1265 } 1266 } 1267 1268 abstract void initCaches(); 1269 abstract void initAtlas(); 1270 1271 EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) { 1272 int[] attribs = { EGL14.EGL_CONTEXT_CLIENT_VERSION, mGlVersion, EGL_NONE }; 1273 1274 EGLContext context = egl.eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT, 1275 mGlVersion != 0 ? attribs : null); 1276 if (context == null || context == EGL_NO_CONTEXT) { 1277 //noinspection ConstantConditions 1278 throw new IllegalStateException( 1279 "Could not create an EGL context. eglCreateContext failed with error: " + 1280 GLUtils.getEGLErrorString(sEgl.eglGetError())); 1281 } 1282 1283 return context; 1284 } 1285 1286 @Override 1287 void destroy(boolean full) { 1288 if (full && mCanvas != null) { 1289 mCanvas = null; 1290 } 1291 1292 if (!isEnabled() || mDestroyed) { 1293 setEnabled(false); 1294 return; 1295 } 1296 1297 destroySurface(); 1298 setEnabled(false); 1299 1300 mDestroyed = true; 1301 mGl = null; 1302 } 1303 1304 void destroySurface() { 1305 if (mEglSurface != null && mEglSurface != EGL_NO_SURFACE) { 1306 if (mEglSurface.equals(sEgl.eglGetCurrentSurface(EGL_DRAW))) { 1307 sEgl.eglMakeCurrent(sEglDisplay, 1308 EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 1309 } 1310 sEgl.eglDestroySurface(sEglDisplay, mEglSurface); 1311 mEglSurface = null; 1312 } 1313 } 1314 1315 @Override 1316 void invalidate(Surface surface) { 1317 // Cancels any existing buffer to ensure we'll get a buffer 1318 // of the right size before we call eglSwapBuffers 1319 sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 1320 1321 if (mEglSurface != null && mEglSurface != EGL_NO_SURFACE) { 1322 sEgl.eglDestroySurface(sEglDisplay, mEglSurface); 1323 mEglSurface = null; 1324 setEnabled(false); 1325 } 1326 1327 if (surface.isValid()) { 1328 if (!createSurface(surface)) { 1329 return; 1330 } 1331 1332 mUpdateDirtyRegions = true; 1333 1334 if (mCanvas != null) { 1335 setEnabled(true); 1336 } 1337 } 1338 } 1339 1340 private boolean createSurface(Surface surface) { 1341 mEglSurface = sEgl.eglCreateWindowSurface(sEglDisplay, sEglConfig, surface, null); 1342 1343 if (mEglSurface == null || mEglSurface == EGL_NO_SURFACE) { 1344 int error = sEgl.eglGetError(); 1345 if (error == EGL_BAD_NATIVE_WINDOW) { 1346 Log.e(LOG_TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW."); 1347 return false; 1348 } 1349 throw new RuntimeException("createWindowSurface failed " 1350 + GLUtils.getEGLErrorString(error)); 1351 } 1352 1353 if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, mEglContext)) { 1354 throw new IllegalStateException("eglMakeCurrent failed " + 1355 GLUtils.getEGLErrorString(sEgl.eglGetError())); 1356 } 1357 1358 enableDirtyRegions(); 1359 1360 return true; 1361 } 1362 1363 @Override 1364 boolean validate() { 1365 return checkRenderContext() != SURFACE_STATE_ERROR; 1366 } 1367 1368 @Override 1369 void setup(int width, int height) { 1370 if (validate()) { 1371 mCanvas.setViewport(width, height); 1372 mWidth = width; 1373 mHeight = height; 1374 } 1375 } 1376 1377 @Override 1378 int getWidth() { 1379 return mWidth; 1380 } 1381 1382 @Override 1383 int getHeight() { 1384 return mHeight; 1385 } 1386 1387 @Override 1388 HardwareCanvas getCanvas() { 1389 return mCanvas; 1390 } 1391 1392 @Override 1393 void setName(String name) { 1394 mName = name; 1395 } 1396 1397 boolean canDraw() { 1398 return mGl != null && mCanvas != null; 1399 } 1400 1401 int onPreDraw(Rect dirty) { 1402 return DisplayList.STATUS_DONE; 1403 } 1404 1405 void onPostDraw() { 1406 } 1407 1408 class FunctorsRunnable implements Runnable { 1409 View.AttachInfo attachInfo; 1410 1411 @Override 1412 public void run() { 1413 final HardwareRenderer renderer = attachInfo.mHardwareRenderer; 1414 if (renderer == null || !renderer.isEnabled() || renderer != GlRenderer.this) { 1415 return; 1416 } 1417 1418 if (checkRenderContext() != SURFACE_STATE_ERROR) { 1419 int status = mCanvas.invokeFunctors(mRedrawClip); 1420 handleFunctorStatus(attachInfo, status); 1421 } 1422 } 1423 } 1424 1425 @Override 1426 void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks, 1427 Rect dirty) { 1428 if (canDraw()) { 1429 if (!hasDirtyRegions()) { 1430 dirty = null; 1431 } 1432 attachInfo.mIgnoreDirtyState = true; 1433 attachInfo.mDrawingTime = SystemClock.uptimeMillis(); 1434 1435 view.mPrivateFlags |= View.PFLAG_DRAWN; 1436 1437 // We are already on the correct thread 1438 final int surfaceState = checkRenderContextUnsafe(); 1439 if (surfaceState != SURFACE_STATE_ERROR) { 1440 HardwareCanvas canvas = mCanvas; 1441 attachInfo.mHardwareCanvas = canvas; 1442 1443 if (mProfileEnabled) { 1444 mProfileLock.lock(); 1445 } 1446 1447 dirty = beginFrame(canvas, dirty, surfaceState); 1448 1449 DisplayList displayList = buildDisplayList(view, canvas); 1450 1451 // buildDisplayList() calls into user code which can cause 1452 // an eglMakeCurrent to happen with a different surface/context. 1453 // We must therefore check again here. 1454 if (checkRenderContextUnsafe() == SURFACE_STATE_ERROR) { 1455 return; 1456 } 1457 1458 int saveCount = 0; 1459 int status = DisplayList.STATUS_DONE; 1460 1461 long start = getSystemTime(); 1462 try { 1463 status = prepareFrame(dirty); 1464 1465 saveCount = canvas.save(); 1466 callbacks.onHardwarePreDraw(canvas); 1467 1468 if (displayList != null) { 1469 status |= drawDisplayList(attachInfo, canvas, displayList, status); 1470 } else { 1471 // Shouldn't reach here 1472 view.draw(canvas); 1473 } 1474 } catch (Exception e) { 1475 Log.e(LOG_TAG, "An error has occurred while drawing:", e); 1476 } finally { 1477 callbacks.onHardwarePostDraw(canvas); 1478 canvas.restoreToCount(saveCount); 1479 view.mRecreateDisplayList = false; 1480 1481 mDrawDelta = getSystemTime() - start; 1482 1483 if (mDrawDelta > 0) { 1484 mFrameCount++; 1485 1486 debugOverdraw(attachInfo, dirty, canvas, displayList); 1487 debugDirtyRegions(dirty, canvas); 1488 drawProfileData(attachInfo); 1489 } 1490 } 1491 1492 onPostDraw(); 1493 1494 swapBuffers(status); 1495 1496 if (mProfileEnabled) { 1497 mProfileLock.unlock(); 1498 } 1499 1500 attachInfo.mIgnoreDirtyState = false; 1501 } 1502 } 1503 } 1504 1505 abstract void countOverdraw(HardwareCanvas canvas); 1506 abstract float getOverdraw(HardwareCanvas canvas); 1507 1508 private void debugOverdraw(View.AttachInfo attachInfo, Rect dirty, 1509 HardwareCanvas canvas, DisplayList displayList) { 1510 1511 if (mDebugOverdraw == OVERDRAW_TYPE_COUNT) { 1512 if (mDebugOverdrawLayer == null) { 1513 mDebugOverdrawLayer = createHardwareLayer(mWidth, mHeight, true); 1514 } else if (mDebugOverdrawLayer.getWidth() != mWidth || 1515 mDebugOverdrawLayer.getHeight() != mHeight) { 1516 mDebugOverdrawLayer.resize(mWidth, mHeight); 1517 } 1518 1519 if (!mDebugOverdrawLayer.isValid()) { 1520 mDebugOverdraw = -1; 1521 return; 1522 } 1523 1524 HardwareCanvas layerCanvas = mDebugOverdrawLayer.start(canvas, dirty); 1525 countOverdraw(layerCanvas); 1526 final int restoreCount = layerCanvas.save(); 1527 layerCanvas.drawDisplayList(displayList, null, DisplayList.FLAG_CLIP_CHILDREN); 1528 layerCanvas.restoreToCount(restoreCount); 1529 mDebugOverdrawLayer.end(canvas); 1530 1531 float overdraw = getOverdraw(layerCanvas); 1532 DisplayMetrics metrics = attachInfo.mRootView.getResources().getDisplayMetrics(); 1533 1534 drawOverdrawCounter(canvas, overdraw, metrics.density); 1535 } 1536 } 1537 1538 private void drawOverdrawCounter(HardwareCanvas canvas, float overdraw, float density) { 1539 final String text = String.format("%.2fx", overdraw); 1540 final Paint paint = setupPaint(density); 1541 // HSBtoColor will clamp the values in the 0..1 range 1542 paint.setColor(Color.HSBtoColor(0.28f - 0.28f * overdraw / 3.5f, 0.8f, 1.0f)); 1543 1544 canvas.drawText(text, density * 4.0f, mHeight - paint.getFontMetrics().bottom, paint); 1545 } 1546 1547 private Paint setupPaint(float density) { 1548 if (mDebugOverdrawPaint == null) { 1549 mDebugOverdrawPaint = new Paint(); 1550 mDebugOverdrawPaint.setAntiAlias(true); 1551 mDebugOverdrawPaint.setShadowLayer(density * 3.0f, 0.0f, 0.0f, 0xff000000); 1552 mDebugOverdrawPaint.setTextSize(density * 20.0f); 1553 } 1554 return mDebugOverdrawPaint; 1555 } 1556 1557 private DisplayList buildDisplayList(View view, HardwareCanvas canvas) { 1558 if (mDrawDelta <= 0) { 1559 return view.mDisplayList; 1560 } 1561 1562 view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED) 1563 == View.PFLAG_INVALIDATED; 1564 view.mPrivateFlags &= ~View.PFLAG_INVALIDATED; 1565 1566 long buildDisplayListStartTime = startBuildDisplayListProfiling(); 1567 canvas.clearLayerUpdates(); 1568 1569 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList"); 1570 DisplayList displayList = view.getDisplayList(); 1571 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 1572 1573 endBuildDisplayListProfiling(buildDisplayListStartTime); 1574 1575 return displayList; 1576 } 1577 1578 abstract void drawProfileData(View.AttachInfo attachInfo); 1579 1580 private Rect beginFrame(HardwareCanvas canvas, Rect dirty, int surfaceState) { 1581 // We had to change the current surface and/or context, redraw everything 1582 if (surfaceState == SURFACE_STATE_UPDATED) { 1583 dirty = null; 1584 beginFrame(null); 1585 } else { 1586 int[] size = mSurfaceSize; 1587 beginFrame(size); 1588 1589 if (size[1] != mHeight || size[0] != mWidth) { 1590 mWidth = size[0]; 1591 mHeight = size[1]; 1592 1593 canvas.setViewport(mWidth, mHeight); 1594 1595 dirty = null; 1596 } 1597 } 1598 1599 if (mDebugDataProvider != null) dirty = null; 1600 1601 return dirty; 1602 } 1603 1604 private long startBuildDisplayListProfiling() { 1605 if (mProfileEnabled) { 1606 mProfileCurrentFrame += PROFILE_FRAME_DATA_COUNT; 1607 if (mProfileCurrentFrame >= mProfileData.length) { 1608 mProfileCurrentFrame = 0; 1609 } 1610 1611 return System.nanoTime(); 1612 } 1613 return 0; 1614 } 1615 1616 private void endBuildDisplayListProfiling(long getDisplayListStartTime) { 1617 if (mProfileEnabled) { 1618 long now = System.nanoTime(); 1619 float total = (now - getDisplayListStartTime) * 0.000001f; 1620 //noinspection PointlessArithmeticExpression 1621 mProfileData[mProfileCurrentFrame] = total; 1622 } 1623 } 1624 1625 private int prepareFrame(Rect dirty) { 1626 int status; 1627 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "prepareFrame"); 1628 try { 1629 status = onPreDraw(dirty); 1630 } finally { 1631 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 1632 } 1633 return status; 1634 } 1635 1636 private int drawDisplayList(View.AttachInfo attachInfo, HardwareCanvas canvas, 1637 DisplayList displayList, int status) { 1638 1639 long drawDisplayListStartTime = 0; 1640 if (mProfileEnabled) { 1641 drawDisplayListStartTime = System.nanoTime(); 1642 } 1643 1644 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "drawDisplayList"); 1645 try { 1646 status |= canvas.drawDisplayList(displayList, mRedrawClip, 1647 DisplayList.FLAG_CLIP_CHILDREN); 1648 } finally { 1649 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 1650 } 1651 1652 if (mProfileEnabled) { 1653 long now = System.nanoTime(); 1654 float total = (now - drawDisplayListStartTime) * 0.000001f; 1655 mProfileData[mProfileCurrentFrame + 1] = total; 1656 } 1657 1658 handleFunctorStatus(attachInfo, status); 1659 return status; 1660 } 1661 1662 private void swapBuffers(int status) { 1663 if ((status & DisplayList.STATUS_DREW) == DisplayList.STATUS_DREW) { 1664 long eglSwapBuffersStartTime = 0; 1665 if (mProfileEnabled) { 1666 eglSwapBuffersStartTime = System.nanoTime(); 1667 } 1668 1669 sEgl.eglSwapBuffers(sEglDisplay, mEglSurface); 1670 1671 if (mProfileEnabled) { 1672 long now = System.nanoTime(); 1673 float total = (now - eglSwapBuffersStartTime) * 0.000001f; 1674 mProfileData[mProfileCurrentFrame + 2] = total; 1675 } 1676 1677 checkEglErrors(); 1678 } 1679 } 1680 1681 private void debugDirtyRegions(Rect dirty, HardwareCanvas canvas) { 1682 if (mDebugDirtyRegions) { 1683 if (mDebugPaint == null) { 1684 mDebugPaint = new Paint(); 1685 mDebugPaint.setColor(0x7fff0000); 1686 } 1687 1688 if (dirty != null && (mFrameCount & 1) == 0) { 1689 canvas.drawRect(dirty, mDebugPaint); 1690 } 1691 } 1692 } 1693 1694 private void handleFunctorStatus(View.AttachInfo attachInfo, int status) { 1695 // If the draw flag is set, functors will be invoked while executing 1696 // the tree of display lists 1697 if ((status & DisplayList.STATUS_DRAW) != 0) { 1698 if (mRedrawClip.isEmpty()) { 1699 attachInfo.mViewRootImpl.invalidate(); 1700 } else { 1701 attachInfo.mViewRootImpl.invalidateChildInParent(null, mRedrawClip); 1702 mRedrawClip.setEmpty(); 1703 } 1704 } 1705 1706 if ((status & DisplayList.STATUS_INVOKE) != 0 || 1707 attachInfo.mHandler.hasCallbacks(mFunctorsRunnable)) { 1708 attachInfo.mHandler.removeCallbacks(mFunctorsRunnable); 1709 mFunctorsRunnable.attachInfo = attachInfo; 1710 attachInfo.mHandler.postDelayed(mFunctorsRunnable, FUNCTOR_PROCESS_DELAY); 1711 } 1712 } 1713 1714 @Override 1715 void detachFunctor(int functor) { 1716 if (mCanvas != null) { 1717 mCanvas.detachFunctor(functor); 1718 } 1719 } 1720 1721 @Override 1722 boolean attachFunctor(View.AttachInfo attachInfo, int functor) { 1723 if (mCanvas != null) { 1724 mCanvas.attachFunctor(functor); 1725 mFunctorsRunnable.attachInfo = attachInfo; 1726 attachInfo.mHandler.removeCallbacks(mFunctorsRunnable); 1727 attachInfo.mHandler.postDelayed(mFunctorsRunnable, 0); 1728 return true; 1729 } 1730 return false; 1731 } 1732 1733 /** 1734 * Ensures the current EGL context and surface are the ones we expect. 1735 * This method throws an IllegalStateException if invoked from a thread 1736 * that did not initialize EGL. 1737 * 1738 * @return {@link #SURFACE_STATE_ERROR} if the correct EGL context cannot be made current, 1739 * {@link #SURFACE_STATE_UPDATED} if the EGL context was changed or 1740 * {@link #SURFACE_STATE_SUCCESS} if the EGL context was the correct one 1741 * 1742 * @see #checkRenderContextUnsafe() 1743 */ 1744 int checkRenderContext() { 1745 if (mEglThread != Thread.currentThread()) { 1746 throw new IllegalStateException("Hardware acceleration can only be used with a " + 1747 "single UI thread.\nOriginal thread: " + mEglThread + "\n" + 1748 "Current thread: " + Thread.currentThread()); 1749 } 1750 1751 return checkRenderContextUnsafe(); 1752 } 1753 1754 /** 1755 * Ensures the current EGL context and surface are the ones we expect. 1756 * This method does not check the current thread. 1757 * 1758 * @return {@link #SURFACE_STATE_ERROR} if the correct EGL context cannot be made current, 1759 * {@link #SURFACE_STATE_UPDATED} if the EGL context was changed or 1760 * {@link #SURFACE_STATE_SUCCESS} if the EGL context was the correct one 1761 * 1762 * @see #checkRenderContext() 1763 */ 1764 private int checkRenderContextUnsafe() { 1765 if (!mEglSurface.equals(sEgl.eglGetCurrentSurface(EGL_DRAW)) || 1766 !mEglContext.equals(sEgl.eglGetCurrentContext())) { 1767 if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, mEglContext)) { 1768 Log.e(LOG_TAG, "eglMakeCurrent failed " + 1769 GLUtils.getEGLErrorString(sEgl.eglGetError())); 1770 fallback(true); 1771 return SURFACE_STATE_ERROR; 1772 } else { 1773 if (mUpdateDirtyRegions) { 1774 enableDirtyRegions(); 1775 mUpdateDirtyRegions = false; 1776 } 1777 return SURFACE_STATE_UPDATED; 1778 } 1779 } 1780 return SURFACE_STATE_SUCCESS; 1781 } 1782 1783 private static int dpToPx(int dp, float density) { 1784 return (int) (dp * density + 0.5f); 1785 } 1786 1787 class DrawPerformanceDataProvider extends GraphDataProvider { 1788 private final int mGraphType; 1789 1790 private int mVerticalUnit; 1791 private int mHorizontalUnit; 1792 private int mHorizontalMargin; 1793 private int mThresholdStroke; 1794 1795 DrawPerformanceDataProvider(int graphType) { 1796 mGraphType = graphType; 1797 } 1798 1799 @Override 1800 void prepare(DisplayMetrics metrics) { 1801 final float density = metrics.density; 1802 1803 mVerticalUnit = dpToPx(PROFILE_DRAW_DP_PER_MS, density); 1804 mHorizontalUnit = dpToPx(PROFILE_DRAW_WIDTH, density); 1805 mHorizontalMargin = dpToPx(PROFILE_DRAW_MARGIN, density); 1806 mThresholdStroke = dpToPx(PROFILE_DRAW_THRESHOLD_STROKE_WIDTH, density); 1807 } 1808 1809 @Override 1810 int getGraphType() { 1811 return mGraphType; 1812 } 1813 1814 @Override 1815 int getVerticalUnitSize() { 1816 return mVerticalUnit; 1817 } 1818 1819 @Override 1820 int getHorizontalUnitSize() { 1821 return mHorizontalUnit; 1822 } 1823 1824 @Override 1825 int getHorizontaUnitMargin() { 1826 return mHorizontalMargin; 1827 } 1828 1829 @Override 1830 float[] getData() { 1831 return mProfileData; 1832 } 1833 1834 @Override 1835 float getThreshold() { 1836 return 16; 1837 } 1838 1839 @Override 1840 int getFrameCount() { 1841 return mProfileData.length / PROFILE_FRAME_DATA_COUNT; 1842 } 1843 1844 @Override 1845 int getElementCount() { 1846 return PROFILE_FRAME_DATA_COUNT; 1847 } 1848 1849 @Override 1850 int getCurrentFrame() { 1851 return mProfileCurrentFrame / PROFILE_FRAME_DATA_COUNT; 1852 } 1853 1854 @Override 1855 void setupGraphPaint(Paint paint, int elementIndex) { 1856 paint.setColor(PROFILE_DRAW_COLORS[elementIndex]); 1857 if (mGraphType == GRAPH_TYPE_LINES) paint.setStrokeWidth(mThresholdStroke); 1858 } 1859 1860 @Override 1861 void setupThresholdPaint(Paint paint) { 1862 paint.setColor(PROFILE_DRAW_THRESHOLD_COLOR); 1863 paint.setStrokeWidth(mThresholdStroke); 1864 } 1865 1866 @Override 1867 void setupCurrentFramePaint(Paint paint) { 1868 paint.setColor(PROFILE_DRAW_CURRENT_FRAME_COLOR); 1869 if (mGraphType == GRAPH_TYPE_LINES) paint.setStrokeWidth(mThresholdStroke); 1870 } 1871 } 1872 } 1873 1874 /** 1875 * Hardware renderer using OpenGL ES 2.0. 1876 */ 1877 static class Gl20Renderer extends GlRenderer { 1878 private GLES20Canvas mGlCanvas; 1879 1880 private DisplayMetrics mDisplayMetrics; 1881 1882 private static EGLSurface sPbuffer; 1883 private static final Object[] sPbufferLock = new Object[0]; 1884 1885 static class Gl20RendererEglContext extends ManagedEGLContext { 1886 final Handler mHandler = new Handler(); 1887 1888 public Gl20RendererEglContext(EGLContext context) { 1889 super(context); 1890 } 1891 1892 @Override 1893 public void onTerminate(final EGLContext eglContext) { 1894 // Make sure we do this on the correct thread. 1895 if (mHandler.getLooper() != Looper.myLooper()) { 1896 mHandler.post(new Runnable() { 1897 @Override 1898 public void run() { 1899 onTerminate(eglContext); 1900 } 1901 }); 1902 return; 1903 } 1904 1905 synchronized (sEglLock) { 1906 if (sEgl == null) return; 1907 1908 if (EGLImpl.getInitCount(sEglDisplay) == 1) { 1909 usePbufferSurface(eglContext); 1910 GLES20Canvas.terminateCaches(); 1911 1912 sEgl.eglDestroyContext(sEglDisplay, eglContext); 1913 sEglContextStorage.set(null); 1914 sEglContextStorage.remove(); 1915 1916 sEgl.eglDestroySurface(sEglDisplay, sPbuffer); 1917 sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, 1918 EGL_NO_SURFACE, EGL_NO_CONTEXT); 1919 1920 sEgl.eglReleaseThread(); 1921 sEgl.eglTerminate(sEglDisplay); 1922 1923 sEgl = null; 1924 sEglDisplay = null; 1925 sEglConfig = null; 1926 sPbuffer = null; 1927 } 1928 } 1929 } 1930 } 1931 1932 Gl20Renderer(boolean translucent) { 1933 super(2, translucent); 1934 } 1935 1936 @Override 1937 HardwareCanvas createCanvas() { 1938 return mGlCanvas = new GLES20Canvas(mTranslucent); 1939 } 1940 1941 @Override 1942 ManagedEGLContext createManagedContext(EGLContext eglContext) { 1943 return new Gl20Renderer.Gl20RendererEglContext(mEglContext); 1944 } 1945 1946 @Override 1947 int[] getConfig(boolean dirtyRegions) { 1948 //noinspection PointlessBooleanExpression,ConstantConditions 1949 final int stencilSize = GLES20Canvas.getStencilSize(); 1950 final int swapBehavior = dirtyRegions ? EGL14.EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0; 1951 1952 return new int[] { 1953 EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT, 1954 EGL_RED_SIZE, 8, 1955 EGL_GREEN_SIZE, 8, 1956 EGL_BLUE_SIZE, 8, 1957 EGL_ALPHA_SIZE, 8, 1958 EGL_DEPTH_SIZE, 0, 1959 EGL_CONFIG_CAVEAT, EGL_NONE, 1960 EGL_STENCIL_SIZE, stencilSize, 1961 EGL_SURFACE_TYPE, EGL_WINDOW_BIT | swapBehavior, 1962 EGL_NONE 1963 }; 1964 } 1965 1966 @Override 1967 void initCaches() { 1968 if (GLES20Canvas.initCaches()) { 1969 // Caches were (re)initialized, rebind atlas 1970 initAtlas(); 1971 } 1972 } 1973 1974 @Override 1975 void initAtlas() { 1976 IBinder binder = ServiceManager.getService("assetatlas"); 1977 if (binder == null) return; 1978 1979 IAssetAtlas atlas = IAssetAtlas.Stub.asInterface(binder); 1980 try { 1981 if (atlas.isCompatible(android.os.Process.myPpid())) { 1982 GraphicBuffer buffer = atlas.getBuffer(); 1983 if (buffer != null) { 1984 int[] map = atlas.getMap(); 1985 if (map != null) { 1986 GLES20Canvas.initAtlas(buffer, map); 1987 } 1988 // If IAssetAtlas is not the same class as the IBinder 1989 // we are using a remote service and we can safely 1990 // destroy the graphic buffer 1991 if (atlas.getClass() != binder.getClass()) { 1992 buffer.destroy(); 1993 } 1994 } 1995 } 1996 } catch (RemoteException e) { 1997 Log.w(LOG_TAG, "Could not acquire atlas", e); 1998 } 1999 } 2000 2001 @Override 2002 boolean canDraw() { 2003 return super.canDraw() && mGlCanvas != null; 2004 } 2005 2006 @Override 2007 int onPreDraw(Rect dirty) { 2008 return mGlCanvas.onPreDraw(dirty); 2009 } 2010 2011 @Override 2012 void onPostDraw() { 2013 mGlCanvas.onPostDraw(); 2014 } 2015 2016 @Override 2017 void drawProfileData(View.AttachInfo attachInfo) { 2018 if (mDebugDataProvider != null) { 2019 final GraphDataProvider provider = mDebugDataProvider; 2020 initProfileDrawData(attachInfo, provider); 2021 2022 final int height = provider.getVerticalUnitSize(); 2023 final int margin = provider.getHorizontaUnitMargin(); 2024 final int width = provider.getHorizontalUnitSize(); 2025 2026 int x = 0; 2027 int count = 0; 2028 int current = 0; 2029 2030 final float[] data = provider.getData(); 2031 final int elementCount = provider.getElementCount(); 2032 final int graphType = provider.getGraphType(); 2033 2034 int totalCount = provider.getFrameCount() * elementCount; 2035 if (graphType == GraphDataProvider.GRAPH_TYPE_LINES) { 2036 totalCount -= elementCount; 2037 } 2038 2039 for (int i = 0; i < totalCount; i += elementCount) { 2040 if (data[i] < 0.0f) break; 2041 2042 int index = count * 4; 2043 if (i == provider.getCurrentFrame() * elementCount) current = index; 2044 2045 x += margin; 2046 int x2 = x + width; 2047 2048 int y2 = mHeight; 2049 int y1 = (int) (y2 - data[i] * height); 2050 2051 switch (graphType) { 2052 case GraphDataProvider.GRAPH_TYPE_BARS: { 2053 for (int j = 0; j < elementCount; j++) { 2054 //noinspection MismatchedReadAndWriteOfArray 2055 final float[] r = mProfileShapes[j]; 2056 r[index] = x; 2057 r[index + 1] = y1; 2058 r[index + 2] = x2; 2059 r[index + 3] = y2; 2060 2061 y2 = y1; 2062 if (j < elementCount - 1) { 2063 y1 = (int) (y2 - data[i + j + 1] * height); 2064 } 2065 } 2066 } break; 2067 case GraphDataProvider.GRAPH_TYPE_LINES: { 2068 for (int j = 0; j < elementCount; j++) { 2069 //noinspection MismatchedReadAndWriteOfArray 2070 final float[] r = mProfileShapes[j]; 2071 r[index] = (x + x2) * 0.5f; 2072 r[index + 1] = index == 0 ? y1 : r[index - 1]; 2073 r[index + 2] = r[index] + width; 2074 r[index + 3] = y1; 2075 2076 y2 = y1; 2077 if (j < elementCount - 1) { 2078 y1 = (int) (y2 - data[i + j + 1] * height); 2079 } 2080 } 2081 } break; 2082 } 2083 2084 2085 x += width; 2086 count++; 2087 } 2088 2089 x += margin; 2090 2091 drawGraph(graphType, count); 2092 drawCurrentFrame(graphType, current); 2093 drawThreshold(x, height); 2094 } 2095 } 2096 2097 private void drawGraph(int graphType, int count) { 2098 for (int i = 0; i < mProfileShapes.length; i++) { 2099 mDebugDataProvider.setupGraphPaint(mProfilePaint, i); 2100 switch (graphType) { 2101 case GraphDataProvider.GRAPH_TYPE_BARS: 2102 mGlCanvas.drawRects(mProfileShapes[i], count * 4, mProfilePaint); 2103 break; 2104 case GraphDataProvider.GRAPH_TYPE_LINES: 2105 mGlCanvas.drawLines(mProfileShapes[i], 0, count * 4, mProfilePaint); 2106 break; 2107 } 2108 } 2109 } 2110 2111 private void drawCurrentFrame(int graphType, int index) { 2112 if (index >= 0) { 2113 mDebugDataProvider.setupCurrentFramePaint(mProfilePaint); 2114 switch (graphType) { 2115 case GraphDataProvider.GRAPH_TYPE_BARS: 2116 mGlCanvas.drawRect(mProfileShapes[2][index], mProfileShapes[2][index + 1], 2117 mProfileShapes[2][index + 2], mProfileShapes[0][index + 3], 2118 mProfilePaint); 2119 break; 2120 case GraphDataProvider.GRAPH_TYPE_LINES: 2121 mGlCanvas.drawLine(mProfileShapes[2][index], mProfileShapes[2][index + 1], 2122 mProfileShapes[2][index], mHeight, mProfilePaint); 2123 break; 2124 } 2125 } 2126 } 2127 2128 private void drawThreshold(int x, int height) { 2129 float threshold = mDebugDataProvider.getThreshold(); 2130 if (threshold > 0.0f) { 2131 mDebugDataProvider.setupThresholdPaint(mProfilePaint); 2132 int y = (int) (mHeight - threshold * height); 2133 mGlCanvas.drawLine(0.0f, y, x, y, mProfilePaint); 2134 } 2135 } 2136 2137 private void initProfileDrawData(View.AttachInfo attachInfo, GraphDataProvider provider) { 2138 if (mProfileShapes == null) { 2139 final int elementCount = provider.getElementCount(); 2140 final int frameCount = provider.getFrameCount(); 2141 2142 mProfileShapes = new float[elementCount][]; 2143 for (int i = 0; i < elementCount; i++) { 2144 mProfileShapes[i] = new float[frameCount * 4]; 2145 } 2146 2147 mProfilePaint = new Paint(); 2148 } 2149 2150 mProfilePaint.reset(); 2151 if (provider.getGraphType() == GraphDataProvider.GRAPH_TYPE_LINES) { 2152 mProfilePaint.setAntiAlias(true); 2153 } 2154 2155 if (mDisplayMetrics == null) { 2156 mDisplayMetrics = new DisplayMetrics(); 2157 } 2158 2159 attachInfo.mDisplay.getMetrics(mDisplayMetrics); 2160 provider.prepare(mDisplayMetrics); 2161 } 2162 2163 @Override 2164 void destroy(boolean full) { 2165 try { 2166 super.destroy(full); 2167 } finally { 2168 if (full && mGlCanvas != null) { 2169 mGlCanvas = null; 2170 } 2171 } 2172 } 2173 2174 @Override 2175 void pushLayerUpdate(HardwareLayer layer) { 2176 mGlCanvas.pushLayerUpdate(layer); 2177 } 2178 2179 @Override 2180 void cancelLayerUpdate(HardwareLayer layer) { 2181 mGlCanvas.cancelLayerUpdate(layer); 2182 } 2183 2184 @Override 2185 void flushLayerUpdates() { 2186 mGlCanvas.flushLayerUpdates(); 2187 } 2188 2189 @Override 2190 public DisplayList createDisplayList(String name) { 2191 return new GLES20DisplayList(name); 2192 } 2193 2194 @Override 2195 HardwareLayer createHardwareLayer(boolean isOpaque) { 2196 return new GLES20TextureLayer(isOpaque); 2197 } 2198 2199 @Override 2200 public HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque) { 2201 return new GLES20RenderLayer(width, height, isOpaque); 2202 } 2203 2204 @Override 2205 void countOverdraw(HardwareCanvas canvas) { 2206 ((GLES20Canvas) canvas).setCountOverdrawEnabled(true); 2207 } 2208 2209 @Override 2210 float getOverdraw(HardwareCanvas canvas) { 2211 return ((GLES20Canvas) canvas).getOverdraw(); 2212 } 2213 2214 @Override 2215 public SurfaceTexture createSurfaceTexture(HardwareLayer layer) { 2216 return ((GLES20TextureLayer) layer).getSurfaceTexture(); 2217 } 2218 2219 @Override 2220 void setSurfaceTexture(HardwareLayer layer, SurfaceTexture surfaceTexture) { 2221 ((GLES20TextureLayer) layer).setSurfaceTexture(surfaceTexture); 2222 } 2223 2224 @Override 2225 boolean safelyRun(Runnable action) { 2226 boolean needsContext = !isEnabled() || checkRenderContext() == SURFACE_STATE_ERROR; 2227 2228 if (needsContext) { 2229 Gl20RendererEglContext managedContext = 2230 (Gl20RendererEglContext) sEglContextStorage.get(); 2231 if (managedContext == null) return false; 2232 usePbufferSurface(managedContext.getContext()); 2233 } 2234 2235 try { 2236 action.run(); 2237 } finally { 2238 if (needsContext) { 2239 sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, 2240 EGL_NO_SURFACE, EGL_NO_CONTEXT); 2241 } 2242 } 2243 2244 return true; 2245 } 2246 2247 @Override 2248 void destroyLayers(final View view) { 2249 if (view != null) { 2250 safelyRun(new Runnable() { 2251 @Override 2252 public void run() { 2253 if (mCanvas != null) { 2254 mCanvas.clearLayerUpdates(); 2255 } 2256 destroyHardwareLayer(view); 2257 GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS); 2258 } 2259 }); 2260 } 2261 } 2262 2263 private static void destroyHardwareLayer(View view) { 2264 view.destroyLayer(true); 2265 2266 if (view instanceof ViewGroup) { 2267 ViewGroup group = (ViewGroup) view; 2268 2269 int count = group.getChildCount(); 2270 for (int i = 0; i < count; i++) { 2271 destroyHardwareLayer(group.getChildAt(i)); 2272 } 2273 } 2274 } 2275 2276 @Override 2277 void destroyHardwareResources(final View view) { 2278 if (view != null) { 2279 safelyRun(new Runnable() { 2280 @Override 2281 public void run() { 2282 if (mCanvas != null) { 2283 mCanvas.clearLayerUpdates(); 2284 } 2285 destroyResources(view); 2286 GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS); 2287 } 2288 }); 2289 } 2290 } 2291 2292 private static void destroyResources(View view) { 2293 view.destroyHardwareResources(); 2294 2295 if (view instanceof ViewGroup) { 2296 ViewGroup group = (ViewGroup) view; 2297 2298 int count = group.getChildCount(); 2299 for (int i = 0; i < count; i++) { 2300 destroyResources(group.getChildAt(i)); 2301 } 2302 } 2303 } 2304 2305 static HardwareRenderer create(boolean translucent) { 2306 if (GLES20Canvas.isAvailable()) { 2307 return new Gl20Renderer(translucent); 2308 } 2309 return null; 2310 } 2311 2312 static void startTrimMemory(int level) { 2313 if (sEgl == null || sEglConfig == null) return; 2314 2315 Gl20RendererEglContext managedContext = 2316 (Gl20RendererEglContext) sEglContextStorage.get(); 2317 // We do not have OpenGL objects 2318 if (managedContext == null) { 2319 return; 2320 } else { 2321 usePbufferSurface(managedContext.getContext()); 2322 } 2323 2324 if (level >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE) { 2325 GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_FULL); 2326 } else if (level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) { 2327 GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_MODERATE); 2328 } 2329 } 2330 2331 static void endTrimMemory() { 2332 if (sEgl != null && sEglDisplay != null) { 2333 sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 2334 } 2335 } 2336 2337 private static void usePbufferSurface(EGLContext eglContext) { 2338 synchronized (sPbufferLock) { 2339 // Create a temporary 1x1 pbuffer so we have a context 2340 // to clear our OpenGL objects 2341 if (sPbuffer == null) { 2342 sPbuffer = sEgl.eglCreatePbufferSurface(sEglDisplay, sEglConfig, new int[] { 2343 EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE 2344 }); 2345 } 2346 } 2347 sEgl.eglMakeCurrent(sEglDisplay, sPbuffer, sPbuffer, eglContext); 2348 } 2349 } 2350 } 2351