ThreadedRenderer.java revision 767e25ed613201d93d293a4c8ead5a21c0fb2b22
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 17package android.view; 18 19import android.annotation.IntDef; 20import android.annotation.NonNull; 21import android.app.ActivityManager; 22import android.content.Context; 23import android.content.res.TypedArray; 24import android.graphics.Bitmap; 25import android.graphics.Point; 26import android.graphics.Rect; 27import android.graphics.drawable.AnimatedVectorDrawable; 28import android.os.IBinder; 29import android.os.ParcelFileDescriptor; 30import android.os.RemoteException; 31import android.os.ServiceManager; 32import android.os.SystemProperties; 33import android.os.Trace; 34import android.util.Log; 35import android.view.Surface.OutOfResourcesException; 36import android.view.View.AttachInfo; 37import android.view.animation.AnimationUtils; 38 39import com.android.internal.R; 40import com.android.internal.util.VirtualRefBasePtr; 41 42import java.io.File; 43import java.io.FileDescriptor; 44import java.io.PrintWriter; 45import java.lang.annotation.Retention; 46import java.lang.annotation.RetentionPolicy; 47 48/** 49 * Threaded renderer that proxies the rendering to a render thread. Most calls 50 * are currently synchronous. 51 * 52 * The UI thread can block on the RenderThread, but RenderThread must never 53 * block on the UI thread. 54 * 55 * ThreadedRenderer creates an instance of RenderProxy. RenderProxy in turn creates 56 * and manages a CanvasContext on the RenderThread. The CanvasContext is fully managed 57 * by the lifecycle of the RenderProxy. 58 * 59 * Note that although currently the EGL context & surfaces are created & managed 60 * by the render thread, the goal is to move that into a shared structure that can 61 * be managed by both threads. EGLSurface creation & deletion should ideally be 62 * done on the UI thread and not the RenderThread to avoid stalling the 63 * RenderThread with surface buffer allocation. 64 * 65 * @hide 66 */ 67public final class ThreadedRenderer { 68 private static final String LOG_TAG = "ThreadedRenderer"; 69 70 /** 71 * Name of the file that holds the shaders cache. 72 */ 73 private static final String CACHE_PATH_SHADERS = "com.android.opengl.shaders_cache"; 74 private static final String CACHE_PATH_SKIASHADERS = "com.android.skia.shaders_cache"; 75 76 /** 77 * System property used to enable or disable threaded rendering profiling. 78 * The default value of this property is assumed to be false. 79 * 80 * When profiling is enabled, the adb shell dumpsys gfxinfo command will 81 * output extra information about the time taken to execute by the last 82 * frames. 83 * 84 * Possible values: 85 * "true", to enable profiling 86 * "visual_bars", to enable profiling and visualize the results on screen 87 * "false", to disable profiling 88 * 89 * @see #PROFILE_PROPERTY_VISUALIZE_BARS 90 * 91 * @hide 92 */ 93 public static final String PROFILE_PROPERTY = "debug.hwui.profile"; 94 95 /** 96 * Value for {@link #PROFILE_PROPERTY}. When the property is set to this 97 * value, profiling data will be visualized on screen as a bar chart. 98 * 99 * @hide 100 */ 101 public static final String PROFILE_PROPERTY_VISUALIZE_BARS = "visual_bars"; 102 103 /** 104 * System property used to specify the number of frames to be used 105 * when doing threaded rendering profiling. 106 * The default value of this property is #PROFILE_MAX_FRAMES. 107 * 108 * When profiling is enabled, the adb shell dumpsys gfxinfo command will 109 * output extra information about the time taken to execute by the last 110 * frames. 111 * 112 * Possible values: 113 * "60", to set the limit of frames to 60 114 */ 115 static final String PROFILE_MAXFRAMES_PROPERTY = "debug.hwui.profile.maxframes"; 116 117 /** 118 * System property used to debug EGL configuration choice. 119 * 120 * Possible values: 121 * "choice", print the chosen configuration only 122 * "all", print all possible configurations 123 */ 124 static final String PRINT_CONFIG_PROPERTY = "debug.hwui.print_config"; 125 126 /** 127 * Turn on to draw dirty regions every other frame. 128 * 129 * Possible values: 130 * "true", to enable dirty regions debugging 131 * "false", to disable dirty regions debugging 132 * 133 * @hide 134 */ 135 public static final String DEBUG_DIRTY_REGIONS_PROPERTY = "debug.hwui.show_dirty_regions"; 136 137 /** 138 * Turn on to flash hardware layers when they update. 139 * 140 * Possible values: 141 * "true", to enable hardware layers updates debugging 142 * "false", to disable hardware layers updates debugging 143 * 144 * @hide 145 */ 146 public static final String DEBUG_SHOW_LAYERS_UPDATES_PROPERTY = 147 "debug.hwui.show_layers_updates"; 148 149 /** 150 * Controls overdraw debugging. 151 * 152 * Possible values: 153 * "false", to disable overdraw debugging 154 * "show", to show overdraw areas on screen 155 * "count", to display an overdraw counter 156 * 157 * @hide 158 */ 159 public static final String DEBUG_OVERDRAW_PROPERTY = "debug.hwui.overdraw"; 160 161 /** 162 * Value for {@link #DEBUG_OVERDRAW_PROPERTY}. When the property is set to this 163 * value, overdraw will be shown on screen by coloring pixels. 164 * 165 * @hide 166 */ 167 public static final String OVERDRAW_PROPERTY_SHOW = "show"; 168 169 /** 170 * Turn on to debug non-rectangular clip operations. 171 * 172 * Possible values: 173 * "hide", to disable this debug mode 174 * "highlight", highlight drawing commands tested against a non-rectangular clip 175 * "stencil", renders the clip region on screen when set 176 * 177 * @hide 178 */ 179 public static final String DEBUG_SHOW_NON_RECTANGULAR_CLIP_PROPERTY = 180 "debug.hwui.show_non_rect_clip"; 181 182 /** 183 * Sets the FPS devisor to lower the FPS. 184 * 185 * Sets a positive integer as a divisor. 1 (the default value) menas the full FPS, and 2 186 * means half the full FPS. 187 * 188 * 189 * @hide 190 */ 191 public static final String DEBUG_FPS_DIVISOR = "debug.hwui.fps_divisor"; 192 193 public static int EGL_CONTEXT_PRIORITY_HIGH_IMG = 0x3101; 194 public static int EGL_CONTEXT_PRIORITY_MEDIUM_IMG = 0x3102; 195 public static int EGL_CONTEXT_PRIORITY_LOW_IMG = 0x3103; 196 197 static { 198 // Try to check OpenGL support early if possible. 199 isAvailable(); 200 } 201 202 /** 203 * A process can set this flag to false to prevent the use of threaded 204 * rendering. 205 * 206 * @hide 207 */ 208 public static boolean sRendererDisabled = false; 209 210 /** 211 * Further threaded renderer disabling for the system process. 212 * 213 * @hide 214 */ 215 public static boolean sSystemRendererDisabled = false; 216 217 /** 218 * Invoke this method to disable threaded rendering in the current process. 219 * 220 * @hide 221 */ 222 public static void disable(boolean system) { 223 sRendererDisabled = true; 224 if (system) { 225 sSystemRendererDisabled = true; 226 } 227 } 228 229 public static boolean sTrimForeground = false; 230 231 /** 232 * Controls whether or not the renderer should aggressively trim 233 * memory. Note that this must not be set for any process that uses 234 * WebView! This should be only used by system_process or similar 235 * that do not go into the background. 236 */ 237 public static void enableForegroundTrimming() { 238 sTrimForeground = true; 239 } 240 241 private static Boolean sSupportsOpenGL; 242 243 /** 244 * Indicates whether threaded rendering is available under any form for 245 * the view hierarchy. 246 * 247 * @return True if the view hierarchy can potentially be defer rendered, 248 * false otherwise 249 */ 250 public static boolean isAvailable() { 251 if (sSupportsOpenGL != null) { 252 return sSupportsOpenGL.booleanValue(); 253 } 254 if (SystemProperties.getInt("ro.kernel.qemu", 0) == 0) { 255 // Device is not an emulator. 256 sSupportsOpenGL = true; 257 return true; 258 } 259 int qemu_gles = SystemProperties.getInt("qemu.gles", -1); 260 if (qemu_gles == -1) { 261 // In this case, the value of the qemu.gles property is not ready 262 // because the SurfaceFlinger service may not start at this point. 263 return false; 264 } 265 // In the emulator this property will be set > 0 when OpenGL ES 2.0 is 266 // enabled, 0 otherwise. On old emulator versions it will be undefined. 267 sSupportsOpenGL = qemu_gles > 0; 268 return sSupportsOpenGL.booleanValue(); 269 } 270 271 /** 272 * Sets the directory to use as a persistent storage for threaded rendering 273 * resources. 274 * 275 * @param cacheDir A directory the current process can write to 276 * 277 * @hide 278 */ 279 public static void setupDiskCache(File cacheDir) { 280 ThreadedRenderer.setupShadersDiskCache( 281 new File(cacheDir, CACHE_PATH_SHADERS).getAbsolutePath(), 282 new File(cacheDir, CACHE_PATH_SKIASHADERS).getAbsolutePath()); 283 } 284 285 /** 286 * Creates a threaded renderer using OpenGL. 287 * 288 * @param translucent True if the surface is translucent, false otherwise 289 * 290 * @return A threaded renderer backed by OpenGL. 291 */ 292 public static ThreadedRenderer create(Context context, boolean translucent, String name) { 293 ThreadedRenderer renderer = null; 294 if (isAvailable()) { 295 renderer = new ThreadedRenderer(context, translucent, name); 296 } 297 return renderer; 298 } 299 300 /** 301 * Invoke this method when the system is running out of memory. This 302 * method will attempt to recover as much memory as possible, based on 303 * the specified hint. 304 * 305 * @param level Hint about the amount of memory that should be trimmed, 306 * see {@link android.content.ComponentCallbacks} 307 */ 308 public static void trimMemory(int level) { 309 nTrimMemory(level); 310 } 311 312 public static void overrideProperty(@NonNull String name, @NonNull String value) { 313 if (name == null || value == null) { 314 throw new IllegalArgumentException("name and value must be non-null"); 315 } 316 nOverrideProperty(name, value); 317 } 318 319 // Keep in sync with DrawFrameTask.h SYNC_* flags 320 // Nothing interesting to report 321 private static final int SYNC_OK = 0; 322 // Needs a ViewRoot invalidate 323 private static final int SYNC_INVALIDATE_REQUIRED = 1 << 0; 324 // Spoiler: the reward is GPU-accelerated drawing, better find that Surface! 325 private static final int SYNC_LOST_SURFACE_REWARD_IF_FOUND = 1 << 1; 326 // setStopped is true, drawing is false 327 // TODO: Remove this and SYNC_LOST_SURFACE_REWARD_IF_FOUND? 328 // This flag isn't really used as there's nothing that we care to do 329 // in response, so it really just exists to differentiate from LOST_SURFACE 330 // but possibly both can just be deleted. 331 private static final int SYNC_CONTEXT_IS_STOPPED = 1 << 2; 332 333 private static final String[] VISUALIZERS = { 334 PROFILE_PROPERTY_VISUALIZE_BARS, 335 }; 336 337 private static final int FLAG_DUMP_FRAMESTATS = 1 << 0; 338 private static final int FLAG_DUMP_RESET = 1 << 1; 339 private static final int FLAG_DUMP_ALL = FLAG_DUMP_FRAMESTATS; 340 341 @IntDef(flag = true, prefix = { "FLAG_DUMP_" }, value = { 342 FLAG_DUMP_FRAMESTATS, 343 FLAG_DUMP_RESET 344 }) 345 @Retention(RetentionPolicy.SOURCE) 346 public @interface DumpFlags {} 347 348 // Size of the rendered content. 349 private int mWidth, mHeight; 350 351 // Actual size of the drawing surface. 352 private int mSurfaceWidth, mSurfaceHeight; 353 354 // Insets between the drawing surface and rendered content. These are 355 // applied as translation when updating the root render node. 356 private int mInsetTop, mInsetLeft; 357 358 // Whether the surface has insets. Used to protect opacity. 359 private boolean mHasInsets; 360 361 // Light and shadow properties specified by the theme. 362 private final float mLightY; 363 private final float mLightZ; 364 private final float mLightRadius; 365 private final int mAmbientShadowAlpha; 366 private final int mSpotShadowAlpha; 367 368 private long mNativeProxy; 369 private boolean mInitialized = false; 370 private RenderNode mRootNode; 371 private boolean mRootNodeNeedsUpdate; 372 373 private boolean mEnabled; 374 private boolean mRequested = true; 375 private boolean mIsOpaque = false; 376 377 ThreadedRenderer(Context context, boolean translucent, String name) { 378 final TypedArray a = context.obtainStyledAttributes(null, R.styleable.Lighting, 0, 0); 379 mLightY = a.getDimension(R.styleable.Lighting_lightY, 0); 380 mLightZ = a.getDimension(R.styleable.Lighting_lightZ, 0); 381 mLightRadius = a.getDimension(R.styleable.Lighting_lightRadius, 0); 382 mAmbientShadowAlpha = 383 (int) (255 * a.getFloat(R.styleable.Lighting_ambientShadowAlpha, 0) + 0.5f); 384 mSpotShadowAlpha = (int) (255 * a.getFloat(R.styleable.Lighting_spotShadowAlpha, 0) + 0.5f); 385 a.recycle(); 386 387 long rootNodePtr = nCreateRootRenderNode(); 388 mRootNode = RenderNode.adopt(rootNodePtr); 389 mRootNode.setClipToBounds(false); 390 mIsOpaque = !translucent; 391 mNativeProxy = nCreateProxy(translucent, rootNodePtr); 392 nSetName(mNativeProxy, name); 393 394 ProcessInitializer.sInstance.init(context, mNativeProxy); 395 396 loadSystemProperties(); 397 } 398 399 /** 400 * Destroys the threaded rendering context. 401 */ 402 void destroy() { 403 mInitialized = false; 404 updateEnabledState(null); 405 nDestroy(mNativeProxy, mRootNode.mNativeRenderNode); 406 } 407 408 /** 409 * Indicates whether threaded rendering is currently enabled. 410 * 411 * @return True if threaded rendering is in use, false otherwise. 412 */ 413 boolean isEnabled() { 414 return mEnabled; 415 } 416 417 /** 418 * Indicates whether threaded rendering is currently enabled. 419 * 420 * @param enabled True if the threaded renderer is in use, false otherwise. 421 */ 422 void setEnabled(boolean enabled) { 423 mEnabled = enabled; 424 } 425 426 /** 427 * Indicates whether threaded rendering is currently request but not 428 * necessarily enabled yet. 429 * 430 * @return True if requested, false otherwise. 431 */ 432 boolean isRequested() { 433 return mRequested; 434 } 435 436 /** 437 * Indicates whether threaded rendering is currently requested but not 438 * necessarily enabled yet. 439 */ 440 void setRequested(boolean requested) { 441 mRequested = requested; 442 } 443 444 private void updateEnabledState(Surface surface) { 445 if (surface == null || !surface.isValid()) { 446 setEnabled(false); 447 } else { 448 setEnabled(mInitialized); 449 } 450 } 451 452 /** 453 * Initializes the threaded renderer for the specified surface. 454 * 455 * @param surface The surface to render 456 * 457 * @return True if the initialization was successful, false otherwise. 458 */ 459 boolean initialize(Surface surface) throws OutOfResourcesException { 460 boolean status = !mInitialized; 461 mInitialized = true; 462 updateEnabledState(surface); 463 nInitialize(mNativeProxy, surface); 464 return status; 465 } 466 467 /** 468 * Initializes the threaded renderer for the specified surface and setup the 469 * renderer for drawing, if needed. This is invoked when the ViewAncestor has 470 * potentially lost the threaded renderer. The threaded renderer should be 471 * reinitialized and setup when the render {@link #isRequested()} and 472 * {@link #isEnabled()}. 473 * 474 * @param width The width of the drawing surface. 475 * @param height The height of the drawing surface. 476 * @param attachInfo Information about the window. 477 * @param surface The surface to render 478 * @param surfaceInsets The drawing surface insets to apply 479 * 480 * @return true if the surface was initialized, false otherwise. Returning 481 * false might mean that the surface was already initialized. 482 */ 483 boolean initializeIfNeeded(int width, int height, View.AttachInfo attachInfo, 484 Surface surface, Rect surfaceInsets) throws OutOfResourcesException { 485 if (isRequested()) { 486 // We lost the gl context, so recreate it. 487 if (!isEnabled()) { 488 if (initialize(surface)) { 489 setup(width, height, attachInfo, surfaceInsets); 490 return true; 491 } 492 } 493 } 494 return false; 495 } 496 497 /** 498 * Updates the threaded renderer for the specified surface. 499 * 500 * @param surface The surface to render 501 */ 502 void updateSurface(Surface surface) throws OutOfResourcesException { 503 updateEnabledState(surface); 504 nUpdateSurface(mNativeProxy, surface); 505 } 506 507 /** 508 * Halts any current rendering into the surface. Use this if it is unclear whether 509 * or not the surface used by the ThreadedRenderer will be changing. It 510 * Suspends any rendering into the surface, but will not do any destruction. 511 * 512 * Any subsequent draws will override the pause, resuming normal operation. 513 */ 514 boolean pauseSurface(Surface surface) { 515 return nPauseSurface(mNativeProxy, surface); 516 } 517 518 /** 519 * Hard stops or resumes rendering into the surface. This flag is used to 520 * determine whether or not it is safe to use the given surface *at all* 521 */ 522 void setStopped(boolean stopped) { 523 nSetStopped(mNativeProxy, stopped); 524 } 525 526 /** 527 * Destroys all hardware rendering resources associated with the specified 528 * view hierarchy. 529 * 530 * @param view The root of the view hierarchy 531 */ 532 void destroyHardwareResources(View view) { 533 destroyResources(view); 534 nDestroyHardwareResources(mNativeProxy); 535 } 536 537 private static void destroyResources(View view) { 538 view.destroyHardwareResources(); 539 } 540 541 /** 542 * Detaches the layer's surface texture from the GL context and releases 543 * the texture id 544 */ 545 void detachSurfaceTexture(long hardwareLayer) { 546 nDetachSurfaceTexture(mNativeProxy, hardwareLayer); 547 } 548 549 /** 550 * Sets up the renderer for drawing. 551 * 552 * @param width The width of the drawing surface. 553 * @param height The height of the drawing surface. 554 * @param attachInfo Information about the window. 555 * @param surfaceInsets The drawing surface insets to apply 556 */ 557 void setup(int width, int height, AttachInfo attachInfo, Rect surfaceInsets) { 558 mWidth = width; 559 mHeight = height; 560 561 if (surfaceInsets != null && (surfaceInsets.left != 0 || surfaceInsets.right != 0 562 || surfaceInsets.top != 0 || surfaceInsets.bottom != 0)) { 563 mHasInsets = true; 564 mInsetLeft = surfaceInsets.left; 565 mInsetTop = surfaceInsets.top; 566 mSurfaceWidth = width + mInsetLeft + surfaceInsets.right; 567 mSurfaceHeight = height + mInsetTop + surfaceInsets.bottom; 568 569 // If the surface has insets, it can't be opaque. 570 setOpaque(false); 571 } else { 572 mHasInsets = false; 573 mInsetLeft = 0; 574 mInsetTop = 0; 575 mSurfaceWidth = width; 576 mSurfaceHeight = height; 577 } 578 579 mRootNode.setLeftTopRightBottom(-mInsetLeft, -mInsetTop, mSurfaceWidth, mSurfaceHeight); 580 nSetup(mNativeProxy, mLightRadius, 581 mAmbientShadowAlpha, mSpotShadowAlpha); 582 583 setLightCenter(attachInfo); 584 } 585 586 /** 587 * Updates the light position based on the position of the window. 588 * 589 * @param attachInfo Information about the window. 590 */ 591 void setLightCenter(AttachInfo attachInfo) { 592 // Adjust light position for window offsets. 593 final Point displaySize = attachInfo.mPoint; 594 attachInfo.mDisplay.getRealSize(displaySize); 595 final float lightX = displaySize.x / 2f - attachInfo.mWindowLeft; 596 final float lightY = mLightY - attachInfo.mWindowTop; 597 598 nSetLightCenter(mNativeProxy, lightX, lightY, mLightZ); 599 } 600 601 /** 602 * Change the ThreadedRenderer's opacity 603 */ 604 void setOpaque(boolean opaque) { 605 mIsOpaque = opaque && !mHasInsets; 606 nSetOpaque(mNativeProxy, mIsOpaque); 607 } 608 609 boolean isOpaque() { 610 return mIsOpaque; 611 } 612 613 /** 614 * Enable/disable wide gamut rendering on this renderer. 615 */ 616 void setWideGamut(boolean wideGamut) { 617 nSetWideGamut(mNativeProxy, wideGamut); 618 } 619 620 /** 621 * Gets the current width of the surface. This is the width that the surface 622 * was last set to in a call to {@link #setup(int, int, View.AttachInfo, Rect)}. 623 * 624 * @return the current width of the surface 625 */ 626 int getWidth() { 627 return mWidth; 628 } 629 630 /** 631 * Gets the current height of the surface. This is the height that the surface 632 * was last set to in a call to {@link #setup(int, int, View.AttachInfo, Rect)}. 633 * 634 * @return the current width of the surface 635 */ 636 int getHeight() { 637 return mHeight; 638 } 639 640 /** 641 * Outputs extra debugging information in the specified file descriptor. 642 */ 643 void dumpGfxInfo(PrintWriter pw, FileDescriptor fd, String[] args) { 644 pw.flush(); 645 // If there's no arguments, eg 'dumpsys gfxinfo', then dump everything. 646 // If there's a targetted package, eg 'dumpsys gfxinfo com.android.systemui', then only 647 // dump the summary information 648 int flags = (args == null || args.length == 0) ? FLAG_DUMP_ALL : 0; 649 for (int i = 0; i < args.length; i++) { 650 switch (args[i]) { 651 case "framestats": 652 flags |= FLAG_DUMP_FRAMESTATS; 653 break; 654 case "reset": 655 flags |= FLAG_DUMP_RESET; 656 break; 657 case "-a": // magic option passed when dumping a bugreport. 658 flags = FLAG_DUMP_ALL; 659 break; 660 } 661 } 662 nDumpProfileInfo(mNativeProxy, fd, flags); 663 } 664 665 /** 666 * Loads system properties used by the renderer. This method is invoked 667 * whenever system properties are modified. Implementations can use this 668 * to trigger live updates of the renderer based on properties. 669 * 670 * @return True if a property has changed. 671 */ 672 boolean loadSystemProperties() { 673 boolean changed = nLoadSystemProperties(mNativeProxy); 674 if (changed) { 675 invalidateRoot(); 676 } 677 return changed; 678 } 679 680 private void updateViewTreeDisplayList(View view) { 681 view.mPrivateFlags |= View.PFLAG_DRAWN; 682 view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED) 683 == View.PFLAG_INVALIDATED; 684 view.mPrivateFlags &= ~View.PFLAG_INVALIDATED; 685 view.updateDisplayListIfDirty(); 686 view.mRecreateDisplayList = false; 687 } 688 689 private void updateRootDisplayList(View view, DrawCallbacks callbacks) { 690 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Record View#draw()"); 691 updateViewTreeDisplayList(view); 692 693 if (mRootNodeNeedsUpdate || !mRootNode.isValid()) { 694 DisplayListCanvas canvas = mRootNode.start(mSurfaceWidth, mSurfaceHeight); 695 try { 696 final int saveCount = canvas.save(); 697 canvas.translate(mInsetLeft, mInsetTop); 698 callbacks.onPreDraw(canvas); 699 700 canvas.insertReorderBarrier(); 701 canvas.drawRenderNode(view.updateDisplayListIfDirty()); 702 canvas.insertInorderBarrier(); 703 704 callbacks.onPostDraw(canvas); 705 canvas.restoreToCount(saveCount); 706 mRootNodeNeedsUpdate = false; 707 } finally { 708 mRootNode.end(canvas); 709 } 710 } 711 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 712 } 713 714 /** 715 * Adds a rendernode to the renderer which can be drawn and changed asynchronously to the 716 * rendernode of the UI thread. 717 * @param node The node to add. 718 * @param placeFront If true, the render node will be placed in front of the content node, 719 * otherwise behind the content node. 720 */ 721 public void addRenderNode(RenderNode node, boolean placeFront) { 722 nAddRenderNode(mNativeProxy, node.mNativeRenderNode, placeFront); 723 } 724 725 /** 726 * Only especially added render nodes can be removed. 727 * @param node The node which was added via addRenderNode which should get removed again. 728 */ 729 public void removeRenderNode(RenderNode node) { 730 nRemoveRenderNode(mNativeProxy, node.mNativeRenderNode); 731 } 732 733 /** 734 * Draws a particular render node. If the node is not the content node, only the additional 735 * nodes will get drawn and the content remains untouched. 736 * @param node The node to be drawn. 737 */ 738 public void drawRenderNode(RenderNode node) { 739 nDrawRenderNode(mNativeProxy, node.mNativeRenderNode); 740 } 741 742 /** 743 * To avoid unnecessary overdrawing of the main content all additionally passed render nodes 744 * will be prevented to overdraw this area. It will be synchronized with the draw call. 745 * This should be updated in the content view's draw call. 746 * @param left The left side of the protected bounds. 747 * @param top The top side of the protected bounds. 748 * @param right The right side of the protected bounds. 749 * @param bottom The bottom side of the protected bounds. 750 */ 751 public void setContentDrawBounds(int left, int top, int right, int bottom) { 752 nSetContentDrawBounds(mNativeProxy, left, top, right, bottom); 753 } 754 755 /** 756 * Interface used to receive callbacks whenever a view is drawn by 757 * a threaded renderer instance. 758 */ 759 interface DrawCallbacks { 760 /** 761 * Invoked before a view is drawn by a threaded renderer. 762 * This method can be used to apply transformations to the 763 * canvas but no drawing command should be issued. 764 * 765 * @param canvas The Canvas used to render the view. 766 */ 767 void onPreDraw(DisplayListCanvas canvas); 768 769 /** 770 * Invoked after a view is drawn by a threaded renderer. 771 * It is safe to invoke drawing commands from this method. 772 * 773 * @param canvas The Canvas used to render the view. 774 */ 775 void onPostDraw(DisplayListCanvas canvas); 776 } 777 778 /** 779 * Indicates that the content drawn by DrawCallbacks needs to 780 * be updated, which will be done by the next call to draw() 781 */ 782 void invalidateRoot() { 783 mRootNodeNeedsUpdate = true; 784 } 785 786 /** 787 * Draws the specified view. 788 * 789 * @param view The view to draw. 790 * @param attachInfo AttachInfo tied to the specified view. 791 * @param callbacks Callbacks invoked when drawing happens. 792 */ 793 void draw(View view, AttachInfo attachInfo, DrawCallbacks callbacks) { 794 attachInfo.mIgnoreDirtyState = true; 795 796 final Choreographer choreographer = attachInfo.mViewRootImpl.mChoreographer; 797 choreographer.mFrameInfo.markDrawStart(); 798 799 updateRootDisplayList(view, callbacks); 800 801 attachInfo.mIgnoreDirtyState = false; 802 803 // register animating rendernodes which started animating prior to renderer 804 // creation, which is typical for animators started prior to first draw 805 if (attachInfo.mPendingAnimatingRenderNodes != null) { 806 final int count = attachInfo.mPendingAnimatingRenderNodes.size(); 807 for (int i = 0; i < count; i++) { 808 registerAnimatingRenderNode( 809 attachInfo.mPendingAnimatingRenderNodes.get(i)); 810 } 811 attachInfo.mPendingAnimatingRenderNodes.clear(); 812 // We don't need this anymore as subsequent calls to 813 // ViewRootImpl#attachRenderNodeAnimator will go directly to us. 814 attachInfo.mPendingAnimatingRenderNodes = null; 815 } 816 817 final long[] frameInfo = choreographer.mFrameInfo.mFrameInfo; 818 int syncResult = nSyncAndDrawFrame(mNativeProxy, frameInfo, frameInfo.length); 819 if ((syncResult & SYNC_LOST_SURFACE_REWARD_IF_FOUND) != 0) { 820 setEnabled(false); 821 attachInfo.mViewRootImpl.mSurface.release(); 822 // Invalidate since we failed to draw. This should fetch a Surface 823 // if it is still needed or do nothing if we are no longer drawing 824 attachInfo.mViewRootImpl.invalidate(); 825 } 826 if ((syncResult & SYNC_INVALIDATE_REQUIRED) != 0) { 827 attachInfo.mViewRootImpl.invalidate(); 828 } 829 } 830 831 static void invokeFunctor(long functor, boolean waitForCompletion) { 832 nInvokeFunctor(functor, waitForCompletion); 833 } 834 835 /** 836 * Creates a new hardware layer. A hardware layer built by calling this 837 * method will be treated as a texture layer, instead of as a render target. 838 * 839 * @return A hardware layer 840 */ 841 TextureLayer createTextureLayer() { 842 long layer = nCreateTextureLayer(mNativeProxy); 843 return TextureLayer.adoptTextureLayer(this, layer); 844 } 845 846 847 void buildLayer(RenderNode node) { 848 nBuildLayer(mNativeProxy, node.getNativeDisplayList()); 849 } 850 851 852 boolean copyLayerInto(final TextureLayer layer, final Bitmap bitmap) { 853 return nCopyLayerInto(mNativeProxy, 854 layer.getDeferredLayerUpdater(), bitmap); 855 } 856 857 /** 858 * Indicates that the specified hardware layer needs to be updated 859 * as soon as possible. 860 * 861 * @param layer The hardware layer that needs an update 862 */ 863 void pushLayerUpdate(TextureLayer layer) { 864 nPushLayerUpdate(mNativeProxy, layer.getDeferredLayerUpdater()); 865 } 866 867 /** 868 * Tells the HardwareRenderer that the layer is destroyed. The renderer 869 * should remove the layer from any update queues. 870 */ 871 void onLayerDestroyed(TextureLayer layer) { 872 nCancelLayerUpdate(mNativeProxy, layer.getDeferredLayerUpdater()); 873 } 874 875 /** 876 * Blocks until all previously queued work has completed. 877 */ 878 void fence() { 879 nFence(mNativeProxy); 880 } 881 882 /** 883 * Prevents any further drawing until draw() is called. This is a signal 884 * that the contents of the RenderNode tree are no longer safe to play back. 885 * In practice this usually means that there are Functor pointers in the 886 * display list that are no longer valid. 887 */ 888 void stopDrawing() { 889 nStopDrawing(mNativeProxy); 890 } 891 892 /** 893 * Called by {@link ViewRootImpl} when a new performTraverals is scheduled. 894 */ 895 public void notifyFramePending() { 896 nNotifyFramePending(mNativeProxy); 897 } 898 899 900 void registerAnimatingRenderNode(RenderNode animator) { 901 nRegisterAnimatingRenderNode(mRootNode.mNativeRenderNode, animator.mNativeRenderNode); 902 } 903 904 void registerVectorDrawableAnimator( 905 AnimatedVectorDrawable.VectorDrawableAnimatorRT animator) { 906 nRegisterVectorDrawableAnimator(mRootNode.mNativeRenderNode, 907 animator.getAnimatorNativePtr()); 908 } 909 910 public void serializeDisplayListTree() { 911 nSerializeDisplayListTree(mNativeProxy); 912 } 913 914 public static int copySurfaceInto(Surface surface, Rect srcRect, Bitmap bitmap) { 915 if (srcRect == null) { 916 // Empty rect means entire surface 917 return nCopySurfaceInto(surface, 0, 0, 0, 0, bitmap); 918 } else { 919 return nCopySurfaceInto(surface, srcRect.left, srcRect.top, 920 srcRect.right, srcRect.bottom, bitmap); 921 } 922 } 923 924 /** 925 * Creates a {@link android.graphics.Bitmap.Config#HARDWARE} bitmap from the given 926 * RenderNode. Note that the RenderNode should be created as a root node (so x/y of 0,0), and 927 * not the RenderNode from a View. 928 **/ 929 public static Bitmap createHardwareBitmap(RenderNode node, int width, int height) { 930 return nCreateHardwareBitmap(node.getNativeDisplayList(), width, height); 931 } 932 933 /** 934 * Sets whether or not high contrast text rendering is enabled. The setting is global 935 * but only affects content rendered after the change is made. 936 */ 937 public static void setHighContrastText(boolean highContrastText) { 938 nSetHighContrastText(highContrastText); 939 } 940 941 /** 942 * If set RenderThread will avoid doing any IPC using instead a fake vsync & DisplayInfo source 943 */ 944 public static void setIsolatedProcess(boolean isIsolated) { 945 nSetIsolatedProcess(isIsolated); 946 } 947 948 /** 949 * If set extra graphics debugging abilities will be enabled such as dumping skp 950 */ 951 public static void setDebuggingEnabled(boolean enable) { 952 nSetDebuggingEnabled(enable); 953 } 954 955 @Override 956 protected void finalize() throws Throwable { 957 try { 958 nDeleteProxy(mNativeProxy); 959 mNativeProxy = 0; 960 } finally { 961 super.finalize(); 962 } 963 } 964 965 /** 966 * Basic synchronous renderer. Currently only used to render the Magnifier, so use with care. 967 * TODO: deduplicate against ThreadedRenderer. 968 * 969 * @hide 970 */ 971 public static class SimpleRenderer { 972 private final RenderNode mRootNode; 973 private long mNativeProxy; 974 private final float mLightY, mLightZ; 975 private Surface mSurface; 976 private final FrameInfo mFrameInfo = new FrameInfo(); 977 978 public SimpleRenderer(final Context context, final String name, final Surface surface) { 979 final TypedArray a = context.obtainStyledAttributes(null, R.styleable.Lighting, 0, 0); 980 mLightY = a.getDimension(R.styleable.Lighting_lightY, 0); 981 mLightZ = a.getDimension(R.styleable.Lighting_lightZ, 0); 982 final float lightRadius = a.getDimension(R.styleable.Lighting_lightRadius, 0); 983 final int ambientShadowAlpha = 984 (int) (255 * a.getFloat(R.styleable.Lighting_ambientShadowAlpha, 0) + 0.5f); 985 final int spotShadowAlpha = 986 (int) (255 * a.getFloat(R.styleable.Lighting_spotShadowAlpha, 0) + 0.5f); 987 a.recycle(); 988 989 final long rootNodePtr = nCreateRootRenderNode(); 990 mRootNode = RenderNode.adopt(rootNodePtr); 991 mRootNode.setClipToBounds(false); 992 mNativeProxy = nCreateProxy(true /* translucent */, rootNodePtr); 993 nSetName(mNativeProxy, name); 994 995 ProcessInitializer.sInstance.init(context, mNativeProxy); 996 nLoadSystemProperties(mNativeProxy); 997 998 nSetup(mNativeProxy, lightRadius, ambientShadowAlpha, spotShadowAlpha); 999 1000 mSurface = surface; 1001 nUpdateSurface(mNativeProxy, surface); 1002 } 1003 1004 /** 1005 * Set the light center. 1006 */ 1007 public void setLightCenter(final Display display, 1008 final int windowLeft, final int windowTop) { 1009 // Adjust light position for window offsets. 1010 final Point displaySize = new Point(); 1011 display.getRealSize(displaySize); 1012 final float lightX = displaySize.x / 2f - windowLeft; 1013 final float lightY = mLightY - windowTop; 1014 1015 nSetLightCenter(mNativeProxy, lightX, lightY, mLightZ); 1016 } 1017 1018 public RenderNode getRootNode() { 1019 return mRootNode; 1020 } 1021 1022 /** 1023 * Draw the surface. 1024 */ 1025 public void draw(final FrameDrawingCallback callback) { 1026 final long vsync = AnimationUtils.currentAnimationTimeMillis() * 1000000L; 1027 mFrameInfo.setVsync(vsync, vsync); 1028 mFrameInfo.addFlags(1 << 2 /* VSYNC */); 1029 if (callback != null) { 1030 nSetFrameCallback(mNativeProxy, callback); 1031 } 1032 nSyncAndDrawFrame(mNativeProxy, mFrameInfo.mFrameInfo, mFrameInfo.mFrameInfo.length); 1033 } 1034 1035 /** 1036 * Destroy the renderer. 1037 */ 1038 public void destroy() { 1039 mSurface = null; 1040 nDestroy(mNativeProxy, mRootNode.mNativeRenderNode); 1041 } 1042 1043 @Override 1044 protected void finalize() throws Throwable { 1045 try { 1046 nDeleteProxy(mNativeProxy); 1047 mNativeProxy = 0; 1048 } finally { 1049 super.finalize(); 1050 } 1051 } 1052 } 1053 1054 /** 1055 * Interface used to receive callbacks when a frame is being drawn. 1056 */ 1057 public interface FrameDrawingCallback { 1058 /** 1059 * Invoked during a frame drawing. 1060 * 1061 * @param frame The id of the frame being drawn. 1062 */ 1063 void onFrameDraw(long frame); 1064 } 1065 1066 private static class ProcessInitializer { 1067 static ProcessInitializer sInstance = new ProcessInitializer(); 1068 1069 private boolean mInitialized = false; 1070 1071 private Context mAppContext; 1072 private IGraphicsStats mGraphicsStatsService; 1073 private IGraphicsStatsCallback mGraphicsStatsCallback = new IGraphicsStatsCallback.Stub() { 1074 @Override 1075 public void onRotateGraphicsStatsBuffer() throws RemoteException { 1076 rotateBuffer(); 1077 } 1078 }; 1079 1080 private ProcessInitializer() {} 1081 1082 synchronized void init(Context context, long renderProxy) { 1083 if (mInitialized) return; 1084 mInitialized = true; 1085 mAppContext = context.getApplicationContext(); 1086 1087 initSched(renderProxy); 1088 1089 if (mAppContext != null) { 1090 initGraphicsStats(); 1091 } 1092 } 1093 1094 private void initSched(long renderProxy) { 1095 try { 1096 int tid = nGetRenderThreadTid(renderProxy); 1097 ActivityManager.getService().setRenderThread(tid); 1098 } catch (Throwable t) { 1099 Log.w(LOG_TAG, "Failed to set scheduler for RenderThread", t); 1100 } 1101 } 1102 1103 private void initGraphicsStats() { 1104 try { 1105 IBinder binder = ServiceManager.getService("graphicsstats"); 1106 if (binder == null) return; 1107 mGraphicsStatsService = IGraphicsStats.Stub.asInterface(binder); 1108 requestBuffer(); 1109 } catch (Throwable t) { 1110 Log.w(LOG_TAG, "Could not acquire gfx stats buffer", t); 1111 } 1112 } 1113 1114 private void rotateBuffer() { 1115 nRotateProcessStatsBuffer(); 1116 requestBuffer(); 1117 } 1118 1119 private void requestBuffer() { 1120 try { 1121 final String pkg = mAppContext.getApplicationInfo().packageName; 1122 ParcelFileDescriptor pfd = mGraphicsStatsService 1123 .requestBufferForProcess(pkg, mGraphicsStatsCallback); 1124 nSetProcessStatsBuffer(pfd.getFd()); 1125 pfd.close(); 1126 } catch (Throwable t) { 1127 Log.w(LOG_TAG, "Could not acquire gfx stats buffer", t); 1128 } 1129 } 1130 } 1131 1132 void addFrameMetricsObserver(FrameMetricsObserver observer) { 1133 long nativeObserver = nAddFrameMetricsObserver(mNativeProxy, observer); 1134 observer.mNative = new VirtualRefBasePtr(nativeObserver); 1135 } 1136 1137 void removeFrameMetricsObserver(FrameMetricsObserver observer) { 1138 nRemoveFrameMetricsObserver(mNativeProxy, observer.mNative.get()); 1139 observer.mNative = null; 1140 } 1141 1142 /** b/68769804: For low FPS experiments. */ 1143 public static void setFPSDivisor(int divisor) { 1144 nHackySetRTAnimationsEnabled(divisor <= 1); 1145 } 1146 1147 /** 1148 * Changes the OpenGL context priority if IMG_context_priority extension is available. Must be 1149 * called before any OpenGL context is created. 1150 * 1151 * @param priority The priority to use. Must be one of EGL_CONTEXT_PRIORITY_* values. 1152 */ 1153 public static void setContextPriority(int priority) { 1154 nSetContextPriority(priority); 1155 } 1156 1157 /** Not actually public - internal use only. This doc to make lint happy */ 1158 public static native void disableVsync(); 1159 1160 static native void setupShadersDiskCache(String cacheFile, String skiaCacheFile); 1161 1162 private static native void nRotateProcessStatsBuffer(); 1163 private static native void nSetProcessStatsBuffer(int fd); 1164 private static native int nGetRenderThreadTid(long nativeProxy); 1165 1166 private static native long nCreateRootRenderNode(); 1167 private static native long nCreateProxy(boolean translucent, long rootRenderNode); 1168 private static native void nDeleteProxy(long nativeProxy); 1169 1170 private static native boolean nLoadSystemProperties(long nativeProxy); 1171 private static native void nSetName(long nativeProxy, String name); 1172 1173 private static native void nInitialize(long nativeProxy, Surface window); 1174 private static native void nUpdateSurface(long nativeProxy, Surface window); 1175 private static native boolean nPauseSurface(long nativeProxy, Surface window); 1176 private static native void nSetStopped(long nativeProxy, boolean stopped); 1177 private static native void nSetup(long nativeProxy, 1178 float lightRadius, int ambientShadowAlpha, int spotShadowAlpha); 1179 private static native void nSetLightCenter(long nativeProxy, 1180 float lightX, float lightY, float lightZ); 1181 private static native void nSetOpaque(long nativeProxy, boolean opaque); 1182 private static native void nSetWideGamut(long nativeProxy, boolean wideGamut); 1183 private static native int nSyncAndDrawFrame(long nativeProxy, long[] frameInfo, int size); 1184 private static native void nDestroy(long nativeProxy, long rootRenderNode); 1185 private static native void nRegisterAnimatingRenderNode(long rootRenderNode, long animatingNode); 1186 private static native void nRegisterVectorDrawableAnimator(long rootRenderNode, long animator); 1187 1188 private static native void nInvokeFunctor(long functor, boolean waitForCompletion); 1189 1190 private static native long nCreateTextureLayer(long nativeProxy); 1191 private static native void nBuildLayer(long nativeProxy, long node); 1192 private static native boolean nCopyLayerInto(long nativeProxy, long layer, Bitmap bitmap); 1193 private static native void nPushLayerUpdate(long nativeProxy, long layer); 1194 private static native void nCancelLayerUpdate(long nativeProxy, long layer); 1195 private static native void nDetachSurfaceTexture(long nativeProxy, long layer); 1196 1197 private static native void nDestroyHardwareResources(long nativeProxy); 1198 private static native void nTrimMemory(int level); 1199 private static native void nOverrideProperty(String name, String value); 1200 1201 private static native void nFence(long nativeProxy); 1202 private static native void nStopDrawing(long nativeProxy); 1203 private static native void nNotifyFramePending(long nativeProxy); 1204 1205 private static native void nSerializeDisplayListTree(long nativeProxy); 1206 1207 private static native void nDumpProfileInfo(long nativeProxy, FileDescriptor fd, 1208 @DumpFlags int dumpFlags); 1209 1210 private static native void nAddRenderNode(long nativeProxy, long rootRenderNode, 1211 boolean placeFront); 1212 private static native void nRemoveRenderNode(long nativeProxy, long rootRenderNode); 1213 private static native void nDrawRenderNode(long nativeProxy, long rootRenderNode); 1214 private static native void nSetContentDrawBounds(long nativeProxy, int left, 1215 int top, int right, int bottom); 1216 private static native void nSetFrameCallback(long nativeProxy, FrameDrawingCallback callback); 1217 1218 private static native long nAddFrameMetricsObserver(long nativeProxy, FrameMetricsObserver observer); 1219 private static native void nRemoveFrameMetricsObserver(long nativeProxy, long nativeObserver); 1220 1221 private static native int nCopySurfaceInto(Surface surface, 1222 int srcLeft, int srcTop, int srcRight, int srcBottom, Bitmap bitmap); 1223 1224 private static native Bitmap nCreateHardwareBitmap(long renderNode, int width, int height); 1225 private static native void nSetHighContrastText(boolean enabled); 1226 // For temporary experimentation b/66945974 1227 private static native void nHackySetRTAnimationsEnabled(boolean enabled); 1228 private static native void nSetDebuggingEnabled(boolean enabled); 1229 private static native void nSetIsolatedProcess(boolean enabled); 1230 private static native void nSetContextPriority(int priority); 1231} 1232