ThreadedRenderer.java revision 9a17da8125c36c82ba73e7f4b3ed80b9c633767f
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.content.Context; 22import android.content.res.TypedArray; 23import android.graphics.Bitmap; 24import android.graphics.Point; 25import android.graphics.Rect; 26import android.os.Binder; 27import android.os.Handler; 28import android.os.IBinder; 29import android.os.Message; 30import android.os.ParcelFileDescriptor; 31import android.os.RemoteException; 32import android.os.ServiceManager; 33import android.os.Trace; 34import android.util.Log; 35import android.view.Surface.OutOfResourcesException; 36import android.view.View.AttachInfo; 37 38import com.android.internal.R; 39import com.android.internal.util.VirtualRefBasePtr; 40 41import java.io.File; 42import java.io.FileDescriptor; 43import java.io.PrintWriter; 44import java.lang.annotation.Retention; 45import java.lang.annotation.RetentionPolicy; 46import java.util.HashSet; 47 48/** 49 * Hardware 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 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 * "false", to disable profiling 98 * 99 * @see #PROFILE_PROPERTY_VISUALIZE_BARS 100 * 101 * @hide 102 */ 103 public static final String PROFILE_PROPERTY = "debug.hwui.profile"; 104 105 /** 106 * Value for {@link #PROFILE_PROPERTY}. When the property is set to this 107 * value, profiling data will be visualized on screen as a bar chart. 108 * 109 * @hide 110 */ 111 public static final String PROFILE_PROPERTY_VISUALIZE_BARS = "visual_bars"; 112 113 /** 114 * System property used to specify the number of frames to be used 115 * when doing hardware rendering profiling. 116 * The default value of this property is #PROFILE_MAX_FRAMES. 117 * 118 * When profiling is enabled, the adb shell dumpsys gfxinfo command will 119 * output extra information about the time taken to execute by the last 120 * frames. 121 * 122 * Possible values: 123 * "60", to set the limit of frames to 60 124 */ 125 static final String PROFILE_MAXFRAMES_PROPERTY = "debug.hwui.profile.maxframes"; 126 127 /** 128 * System property used to debug EGL configuration choice. 129 * 130 * Possible values: 131 * "choice", print the chosen configuration only 132 * "all", print all possible configurations 133 */ 134 static final String PRINT_CONFIG_PROPERTY = "debug.hwui.print_config"; 135 136 /** 137 * Turn on to draw dirty regions every other frame. 138 * 139 * Possible values: 140 * "true", to enable dirty regions debugging 141 * "false", to disable dirty regions debugging 142 * 143 * @hide 144 */ 145 public static final String DEBUG_DIRTY_REGIONS_PROPERTY = "debug.hwui.show_dirty_regions"; 146 147 /** 148 * Turn on to flash hardware layers when they update. 149 * 150 * Possible values: 151 * "true", to enable hardware layers updates debugging 152 * "false", to disable hardware layers updates debugging 153 * 154 * @hide 155 */ 156 public static final String DEBUG_SHOW_LAYERS_UPDATES_PROPERTY = 157 "debug.hwui.show_layers_updates"; 158 159 /** 160 * Controls overdraw debugging. 161 * 162 * Possible values: 163 * "false", to disable overdraw debugging 164 * "show", to show overdraw areas on screen 165 * "count", to display an overdraw counter 166 * 167 * @hide 168 */ 169 public static final String DEBUG_OVERDRAW_PROPERTY = "debug.hwui.overdraw"; 170 171 /** 172 * Value for {@link #DEBUG_OVERDRAW_PROPERTY}. When the property is set to this 173 * value, overdraw will be shown on screen by coloring pixels. 174 * 175 * @hide 176 */ 177 public static final String OVERDRAW_PROPERTY_SHOW = "show"; 178 179 /** 180 * Turn on to debug non-rectangular clip operations. 181 * 182 * Possible values: 183 * "hide", to disable this debug mode 184 * "highlight", highlight drawing commands tested against a non-rectangular clip 185 * "stencil", renders the clip region on screen when set 186 * 187 * @hide 188 */ 189 public static final String DEBUG_SHOW_NON_RECTANGULAR_CLIP_PROPERTY = 190 "debug.hwui.show_non_rect_clip"; 191 192 /** 193 * A process can set this flag to false to prevent the use of hardware 194 * rendering. 195 * 196 * @hide 197 */ 198 public static boolean sRendererDisabled = false; 199 200 /** 201 * Further hardware renderer disabling for the system process. 202 * 203 * @hide 204 */ 205 public static boolean sSystemRendererDisabled = false; 206 207 /** 208 * Invoke this method to disable hardware rendering in the current process. 209 * 210 * @hide 211 */ 212 public static void disable(boolean system) { 213 sRendererDisabled = true; 214 if (system) { 215 sSystemRendererDisabled = true; 216 } 217 } 218 219 public static boolean sTrimForeground = false; 220 221 /** 222 * Controls whether or not the hardware renderer should aggressively 223 * trim memory. Note that this must not be set for any process that 224 * uses WebView! This should be only used by system_process or similar 225 * that do not go into the background. 226 */ 227 public static void enableForegroundTrimming() { 228 sTrimForeground = true; 229 } 230 231 /** 232 * Indicates whether hardware acceleration is available under any form for 233 * the view hierarchy. 234 * 235 * @return True if the view hierarchy can potentially be hardware accelerated, 236 * false otherwise 237 */ 238 public static boolean isAvailable() { 239 return DisplayListCanvas.isAvailable(); 240 } 241 242 /** 243 * Sets the directory to use as a persistent storage for hardware rendering 244 * resources. 245 * 246 * @param cacheDir A directory the current process can write to 247 * 248 * @hide 249 */ 250 public static void setupDiskCache(File cacheDir) { 251 ThreadedRenderer.setupShadersDiskCache(new File(cacheDir, CACHE_PATH_SHADERS).getAbsolutePath()); 252 } 253 254 /** 255 * Sets the library directory to use as a search path for vulkan layers. 256 * 257 * @param libDir A directory that contains vulkan layers 258 * 259 * @hide 260 */ 261 public static void setLibDir(String libDir) { 262 ThreadedRenderer.setupVulkanLayerPath(libDir); 263 } 264 265 /** 266 * Creates a hardware renderer using OpenGL. 267 * 268 * @param translucent True if the surface is translucent, false otherwise 269 * 270 * @return A hardware renderer backed by OpenGL. 271 */ 272 public static ThreadedRenderer create(Context context, boolean translucent) { 273 ThreadedRenderer renderer = null; 274 if (DisplayListCanvas.isAvailable()) { 275 renderer = new ThreadedRenderer(context, translucent); 276 } 277 return renderer; 278 } 279 280 /** 281 * Invoke this method when the system is running out of memory. This 282 * method will attempt to recover as much memory as possible, based on 283 * the specified hint. 284 * 285 * @param level Hint about the amount of memory that should be trimmed, 286 * see {@link android.content.ComponentCallbacks} 287 */ 288 public static void trimMemory(int level) { 289 nTrimMemory(level); 290 } 291 292 public static void overrideProperty(@NonNull String name, @NonNull String value) { 293 if (name == null || value == null) { 294 throw new IllegalArgumentException("name and value must be non-null"); 295 } 296 nOverrideProperty(name, value); 297 } 298 299 public static void dumpProfileData(byte[] data, FileDescriptor fd) { 300 nDumpProfileData(data, fd); 301 } 302 303 // Keep in sync with DrawFrameTask.h SYNC_* flags 304 // Nothing interesting to report 305 private static final int SYNC_OK = 0; 306 // Needs a ViewRoot invalidate 307 private static final int SYNC_INVALIDATE_REQUIRED = 1 << 0; 308 // Spoiler: the reward is GPU-accelerated drawing, better find that Surface! 309 private static final int SYNC_LOST_SURFACE_REWARD_IF_FOUND = 1 << 1; 310 // setStopped is true, drawing is false 311 // TODO: Remove this and SYNC_LOST_SURFACE_REWARD_IF_FOUND? 312 // This flag isn't really used as there's nothing that we care to do 313 // in response, so it really just exists to differentiate from LOST_SURFACE 314 // but possibly both can just be deleted. 315 private static final int SYNC_CONTEXT_IS_STOPPED = 1 << 2; 316 317 private static final String[] VISUALIZERS = { 318 PROFILE_PROPERTY_VISUALIZE_BARS, 319 }; 320 321 private static final int FLAG_DUMP_FRAMESTATS = 1 << 0; 322 private static final int FLAG_DUMP_RESET = 1 << 1; 323 324 @IntDef(flag = true, value = { 325 FLAG_DUMP_FRAMESTATS, FLAG_DUMP_RESET }) 326 @Retention(RetentionPolicy.SOURCE) 327 public @interface DumpFlags {} 328 329 // Size of the rendered content. 330 private int mWidth, mHeight; 331 332 // Actual size of the drawing surface. 333 private int mSurfaceWidth, mSurfaceHeight; 334 335 // Insets between the drawing surface and rendered content. These are 336 // applied as translation when updating the root render node. 337 private int mInsetTop, mInsetLeft; 338 339 // Whether the surface has insets. Used to protect opacity. 340 private boolean mHasInsets; 341 342 // Light and shadow properties specified by the theme. 343 private final float mLightY; 344 private final float mLightZ; 345 private final float mLightRadius; 346 private final int mAmbientShadowAlpha; 347 private final int mSpotShadowAlpha; 348 349 private long mNativeProxy; 350 private boolean mInitialized = false; 351 private RenderNode mRootNode; 352 private Choreographer mChoreographer; 353 private boolean mRootNodeNeedsUpdate; 354 355 // In case of multi threaded render nodes, these bounds indicate the content bounds against 356 // which the backdrop needs to be cropped against. 357 private final Rect mCurrentContentBounds = new Rect(); 358 private final Rect mStagedContentBounds = new Rect(); 359 360 private boolean mEnabled; 361 private boolean mRequested = true; 362 363 ThreadedRenderer(Context context, boolean translucent) { 364 final TypedArray a = context.obtainStyledAttributes(null, R.styleable.Lighting, 0, 0); 365 mLightY = a.getDimension(R.styleable.Lighting_lightY, 0); 366 mLightZ = a.getDimension(R.styleable.Lighting_lightZ, 0); 367 mLightRadius = a.getDimension(R.styleable.Lighting_lightRadius, 0); 368 mAmbientShadowAlpha = 369 (int) (255 * a.getFloat(R.styleable.Lighting_ambientShadowAlpha, 0) + 0.5f); 370 mSpotShadowAlpha = (int) (255 * a.getFloat(R.styleable.Lighting_spotShadowAlpha, 0) + 0.5f); 371 a.recycle(); 372 373 long rootNodePtr = nCreateRootRenderNode(); 374 mRootNode = RenderNode.adopt(rootNodePtr); 375 mRootNode.setClipToBounds(false); 376 mNativeProxy = nCreateProxy(translucent, rootNodePtr); 377 378 ProcessInitializer.sInstance.init(context, mNativeProxy); 379 380 loadSystemProperties(); 381 } 382 383 /** 384 * Destroys the hardware rendering context. 385 */ 386 void destroy() { 387 mInitialized = false; 388 updateEnabledState(null); 389 nDestroy(mNativeProxy, mRootNode.mNativeRenderNode); 390 } 391 392 /** 393 * Indicates whether hardware acceleration is currently enabled. 394 * 395 * @return True if hardware acceleration is in use, false otherwise. 396 */ 397 boolean isEnabled() { 398 return mEnabled; 399 } 400 401 /** 402 * Indicates whether hardware acceleration is currently enabled. 403 * 404 * @param enabled True if the hardware renderer is in use, false otherwise. 405 */ 406 void setEnabled(boolean enabled) { 407 mEnabled = enabled; 408 } 409 410 /** 411 * Indicates whether hardware acceleration is currently request but not 412 * necessarily enabled yet. 413 * 414 * @return True if requested, false otherwise. 415 */ 416 boolean isRequested() { 417 return mRequested; 418 } 419 420 /** 421 * Indicates whether hardware acceleration is currently requested but not 422 * necessarily enabled yet. 423 * 424 * @return True to request hardware acceleration, false otherwise. 425 */ 426 void setRequested(boolean requested) { 427 mRequested = requested; 428 } 429 430 private void updateEnabledState(Surface surface) { 431 if (surface == null || !surface.isValid()) { 432 setEnabled(false); 433 } else { 434 setEnabled(mInitialized); 435 } 436 } 437 438 /** 439 * Initializes the hardware renderer for the specified surface. 440 * 441 * @param surface The surface to hardware accelerate 442 * 443 * @return True if the initialization was successful, false otherwise. 444 */ 445 boolean initialize(Surface surface) throws OutOfResourcesException { 446 boolean status = !mInitialized; 447 mInitialized = true; 448 updateEnabledState(surface); 449 nInitialize(mNativeProxy, surface); 450 return status; 451 } 452 453 /** 454 * Initializes the hardware renderer for the specified surface and setup the 455 * renderer for drawing, if needed. This is invoked when the ViewAncestor has 456 * potentially lost the hardware renderer. The hardware renderer should be 457 * reinitialized and setup when the render {@link #isRequested()} and 458 * {@link #isEnabled()}. 459 * 460 * @param width The width of the drawing surface. 461 * @param height The height of the drawing surface. 462 * @param attachInfo Information about the window. 463 * @param surface The surface to hardware accelerate 464 * @param surfaceInsets The drawing surface insets to apply 465 * 466 * @return true if the surface was initialized, false otherwise. Returning 467 * false might mean that the surface was already initialized. 468 */ 469 boolean initializeIfNeeded(int width, int height, View.AttachInfo attachInfo, 470 Surface surface, Rect surfaceInsets) throws OutOfResourcesException { 471 if (isRequested()) { 472 // We lost the gl context, so recreate it. 473 if (!isEnabled()) { 474 if (initialize(surface)) { 475 setup(width, height, attachInfo, surfaceInsets); 476 return true; 477 } 478 } 479 } 480 return false; 481 } 482 483 /** 484 * Updates the hardware renderer for the specified surface. 485 * 486 * @param surface The surface to hardware accelerate 487 */ 488 void updateSurface(Surface surface) throws OutOfResourcesException { 489 updateEnabledState(surface); 490 nUpdateSurface(mNativeProxy, surface); 491 } 492 493 /** 494 * Halts any current rendering into the surface. Use this if it is unclear whether 495 * or not the surface used by the HardwareRenderer will be changing. It 496 * Suspends any rendering into the surface, but will not do any destruction. 497 * 498 * Any subsequent draws will override the pause, resuming normal operation. 499 */ 500 boolean pauseSurface(Surface surface) { 501 return nPauseSurface(mNativeProxy, surface); 502 } 503 504 /** 505 * Hard stops or resumes rendering into the surface. This flag is used to 506 * determine whether or not it is safe to use the given surface *at all* 507 */ 508 void setStopped(boolean stopped) { 509 nSetStopped(mNativeProxy, stopped); 510 } 511 512 /** 513 * Destroys all hardware rendering resources associated with the specified 514 * view hierarchy. 515 * 516 * @param view The root of the view hierarchy 517 */ 518 void destroyHardwareResources(View view) { 519 destroyResources(view); 520 nDestroyHardwareResources(mNativeProxy); 521 } 522 523 private static void destroyResources(View view) { 524 view.destroyHardwareResources(); 525 526 if (view instanceof ViewGroup) { 527 ViewGroup group = (ViewGroup) view; 528 529 int count = group.getChildCount(); 530 for (int i = 0; i < count; i++) { 531 destroyResources(group.getChildAt(i)); 532 } 533 } 534 } 535 536 /** 537 * This method should be invoked whenever the current hardware renderer 538 * context should be reset. 539 * 540 * @param surface The surface to hardware accelerate 541 */ 542 void invalidate(Surface surface) { 543 updateSurface(surface); 544 } 545 546 /** 547 * Detaches the layer's surface texture from the GL context and releases 548 * the texture id 549 */ 550 void detachSurfaceTexture(long hardwareLayer) { 551 nDetachSurfaceTexture(mNativeProxy, hardwareLayer); 552 } 553 554 /** 555 * Sets up the renderer for drawing. 556 * 557 * @param width The width of the drawing surface. 558 * @param height The height of the drawing surface. 559 * @param attachInfo Information about the window. 560 * @param surfaceInsets The drawing surface insets to apply 561 */ 562 void setup(int width, int height, AttachInfo attachInfo, Rect surfaceInsets) { 563 mWidth = width; 564 mHeight = height; 565 566 if (surfaceInsets != null && (surfaceInsets.left != 0 || surfaceInsets.right != 0 567 || surfaceInsets.top != 0 || surfaceInsets.bottom != 0)) { 568 mHasInsets = true; 569 mInsetLeft = surfaceInsets.left; 570 mInsetTop = surfaceInsets.top; 571 mSurfaceWidth = width + mInsetLeft + surfaceInsets.right; 572 mSurfaceHeight = height + mInsetTop + surfaceInsets.bottom; 573 574 // If the surface has insets, it can't be opaque. 575 setOpaque(false); 576 } else { 577 mHasInsets = false; 578 mInsetLeft = 0; 579 mInsetTop = 0; 580 mSurfaceWidth = width; 581 mSurfaceHeight = height; 582 } 583 584 mRootNode.setLeftTopRightBottom(-mInsetLeft, -mInsetTop, mSurfaceWidth, mSurfaceHeight); 585 nSetup(mNativeProxy, mSurfaceWidth, mSurfaceHeight, mLightRadius, 586 mAmbientShadowAlpha, mSpotShadowAlpha); 587 588 setLightCenter(attachInfo); 589 } 590 591 /** 592 * Updates the light position based on the position of the window. 593 * 594 * @param attachInfo Information about the window. 595 */ 596 void setLightCenter(AttachInfo attachInfo) { 597 // Adjust light position for window offsets. 598 final Point displaySize = attachInfo.mPoint; 599 attachInfo.mDisplay.getRealSize(displaySize); 600 final float lightX = displaySize.x / 2f - attachInfo.mWindowLeft; 601 final float lightY = mLightY - attachInfo.mWindowTop; 602 603 nSetLightCenter(mNativeProxy, lightX, lightY, mLightZ); 604 } 605 606 /** 607 * Change the HardwareRenderer's opacity 608 */ 609 void setOpaque(boolean opaque) { 610 nSetOpaque(mNativeProxy, opaque && !mHasInsets); 611 } 612 613 /** 614 * Gets the current width of the surface. This is the width that the surface 615 * was last set to in a call to {@link #setup(int, int, View.AttachInfo, Rect)}. 616 * 617 * @return the current width of the surface 618 */ 619 int getWidth() { 620 return mWidth; 621 } 622 623 /** 624 * Gets the current height of the surface. This is the height that the surface 625 * was last set to in a call to {@link #setup(int, int, View.AttachInfo, Rect)}. 626 * 627 * @return the current width of the surface 628 */ 629 int getHeight() { 630 return mHeight; 631 } 632 633 /** 634 * Outputs extra debugging information in the specified file descriptor. 635 */ 636 void dumpGfxInfo(PrintWriter pw, FileDescriptor fd, String[] args) { 637 pw.flush(); 638 int flags = 0; 639 for (int i = 0; i < args.length; i++) { 640 switch (args[i]) { 641 case "framestats": 642 flags |= FLAG_DUMP_FRAMESTATS; 643 break; 644 case "reset": 645 flags |= FLAG_DUMP_RESET; 646 break; 647 } 648 } 649 nDumpProfileInfo(mNativeProxy, fd, flags); 650 } 651 652 /** 653 * Loads system properties used by the renderer. This method is invoked 654 * whenever system properties are modified. Implementations can use this 655 * to trigger live updates of the renderer based on properties. 656 * 657 * @return True if a property has changed. 658 */ 659 boolean loadSystemProperties() { 660 boolean changed = nLoadSystemProperties(mNativeProxy); 661 if (changed) { 662 invalidateRoot(); 663 } 664 return changed; 665 } 666 667 private void updateViewTreeDisplayList(View view) { 668 view.mPrivateFlags |= View.PFLAG_DRAWN; 669 view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED) 670 == View.PFLAG_INVALIDATED; 671 view.mPrivateFlags &= ~View.PFLAG_INVALIDATED; 672 view.updateDisplayListIfDirty(); 673 view.mRecreateDisplayList = false; 674 } 675 676 private void updateRootDisplayList(View view, HardwareDrawCallbacks callbacks) { 677 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Record View#draw()"); 678 updateViewTreeDisplayList(view); 679 680 if (mRootNodeNeedsUpdate || !mRootNode.isValid()) { 681 DisplayListCanvas canvas = mRootNode.start(mSurfaceWidth, mSurfaceHeight); 682 try { 683 final int saveCount = canvas.save(); 684 canvas.translate(mInsetLeft, mInsetTop); 685 callbacks.onHardwarePreDraw(canvas); 686 687 canvas.insertReorderBarrier(); 688 canvas.drawRenderNode(view.updateDisplayListIfDirty()); 689 canvas.insertInorderBarrier(); 690 691 callbacks.onHardwarePostDraw(canvas); 692 canvas.restoreToCount(saveCount); 693 mRootNodeNeedsUpdate = false; 694 } finally { 695 mRootNode.end(canvas); 696 } 697 } 698 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 699 } 700 701 /** 702 * Adds a rendernode to the renderer which can be drawn and changed asynchronously to the 703 * rendernode of the UI thread. 704 * @param node The node to add. 705 * @param placeFront If true, the render node will be placed in front of the content node, 706 * otherwise behind the content node. 707 */ 708 public void addRenderNode(RenderNode node, boolean placeFront) { 709 nAddRenderNode(mNativeProxy, node.mNativeRenderNode, placeFront); 710 } 711 712 /** 713 * Only especially added render nodes can be removed. 714 * @param node The node which was added via addRenderNode which should get removed again. 715 */ 716 public void removeRenderNode(RenderNode node) { 717 nRemoveRenderNode(mNativeProxy, node.mNativeRenderNode); 718 } 719 720 /** 721 * Draws a particular render node. If the node is not the content node, only the additional 722 * nodes will get drawn and the content remains untouched. 723 * @param node The node to be drawn. 724 */ 725 public void drawRenderNode(RenderNode node) { 726 nDrawRenderNode(mNativeProxy, node.mNativeRenderNode); 727 } 728 729 /** 730 * To avoid unnecessary overdrawing of the main content all additionally passed render nodes 731 * will be prevented to overdraw this area. It will be synchronized with the draw call. 732 * This should be updated in the content view's draw call. 733 * @param left The left side of the protected bounds. 734 * @param top The top side of the protected bounds. 735 * @param right The right side of the protected bounds. 736 * @param bottom The bottom side of the protected bounds. 737 */ 738 public void setContentDrawBounds(int left, int top, int right, int bottom) { 739 mStagedContentBounds.set(left, top, right, bottom); 740 } 741 742 /** 743 * Interface used to receive callbacks whenever a view is drawn by 744 * a hardware renderer instance. 745 */ 746 interface HardwareDrawCallbacks { 747 /** 748 * Invoked before a view is drawn by a hardware renderer. 749 * This method can be used to apply transformations to the 750 * canvas but no drawing command should be issued. 751 * 752 * @param canvas The Canvas used to render the view. 753 */ 754 void onHardwarePreDraw(DisplayListCanvas canvas); 755 756 /** 757 * Invoked after a view is drawn by a hardware renderer. 758 * It is safe to invoke drawing commands from this method. 759 * 760 * @param canvas The Canvas used to render the view. 761 */ 762 void onHardwarePostDraw(DisplayListCanvas canvas); 763 } 764 765 /** 766 * Indicates that the content drawn by HardwareDrawCallbacks needs to 767 * be updated, which will be done by the next call to draw() 768 */ 769 void invalidateRoot() { 770 mRootNodeNeedsUpdate = true; 771 } 772 773 /** 774 * Draws the specified view. 775 * 776 * @param view The view to draw. 777 * @param attachInfo AttachInfo tied to the specified view. 778 * @param callbacks Callbacks invoked when drawing happens. 779 */ 780 void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks) { 781 attachInfo.mIgnoreDirtyState = true; 782 783 final Choreographer choreographer = attachInfo.mViewRootImpl.mChoreographer; 784 choreographer.mFrameInfo.markDrawStart(); 785 786 updateRootDisplayList(view, callbacks); 787 // The main content view was updating the content bounds and we transfer them to the 788 // renderer. 789 if (!mCurrentContentBounds.equals(mStagedContentBounds)) { 790 mCurrentContentBounds.set(mStagedContentBounds); 791 nSetContentDrawBounds(mNativeProxy, mCurrentContentBounds.left, 792 mCurrentContentBounds.top, mCurrentContentBounds.right, 793 mCurrentContentBounds.bottom); 794 } 795 796 attachInfo.mIgnoreDirtyState = false; 797 798 // register animating rendernodes which started animating prior to renderer 799 // creation, which is typical for animators started prior to first draw 800 if (attachInfo.mPendingAnimatingRenderNodes != null) { 801 final int count = attachInfo.mPendingAnimatingRenderNodes.size(); 802 for (int i = 0; i < count; i++) { 803 registerAnimatingRenderNode( 804 attachInfo.mPendingAnimatingRenderNodes.get(i)); 805 } 806 attachInfo.mPendingAnimatingRenderNodes.clear(); 807 // We don't need this anymore as subsequent calls to 808 // ViewRootImpl#attachRenderNodeAnimator will go directly to us. 809 attachInfo.mPendingAnimatingRenderNodes = null; 810 } 811 812 final long[] frameInfo = choreographer.mFrameInfo.mFrameInfo; 813 int syncResult = nSyncAndDrawFrame(mNativeProxy, frameInfo, frameInfo.length); 814 if ((syncResult & SYNC_LOST_SURFACE_REWARD_IF_FOUND) != 0) { 815 setEnabled(false); 816 attachInfo.mViewRootImpl.mSurface.release(); 817 // Invalidate since we failed to draw. This should fetch a Surface 818 // if it is still needed or do nothing if we are no longer drawing 819 attachInfo.mViewRootImpl.invalidate(); 820 } 821 if ((syncResult & SYNC_INVALIDATE_REQUIRED) != 0) { 822 attachInfo.mViewRootImpl.invalidate(); 823 } 824 } 825 826 static void invokeFunctor(long functor, boolean waitForCompletion) { 827 nInvokeFunctor(functor, waitForCompletion); 828 } 829 830 /** 831 * Creates a new hardware layer. A hardware layer built by calling this 832 * method will be treated as a texture layer, instead of as a render target. 833 * 834 * @return A hardware layer 835 */ 836 HardwareLayer createTextureLayer() { 837 long layer = nCreateTextureLayer(mNativeProxy); 838 return HardwareLayer.adoptTextureLayer(this, layer); 839 } 840 841 842 void buildLayer(RenderNode node) { 843 nBuildLayer(mNativeProxy, node.getNativeDisplayList()); 844 } 845 846 847 boolean copyLayerInto(final HardwareLayer layer, final Bitmap bitmap) { 848 return nCopyLayerInto(mNativeProxy, 849 layer.getDeferredLayerUpdater(), bitmap); 850 } 851 852 /** 853 * Indicates that the specified hardware layer needs to be updated 854 * as soon as possible. 855 * 856 * @param layer The hardware layer that needs an update 857 */ 858 void pushLayerUpdate(HardwareLayer layer) { 859 nPushLayerUpdate(mNativeProxy, layer.getDeferredLayerUpdater()); 860 } 861 862 /** 863 * Tells the HardwareRenderer that the layer is destroyed. The renderer 864 * should remove the layer from any update queues. 865 */ 866 void onLayerDestroyed(HardwareLayer layer) { 867 nCancelLayerUpdate(mNativeProxy, layer.getDeferredLayerUpdater()); 868 } 869 870 /** 871 * Optional, sets the name of the renderer. Useful for debugging purposes. 872 * 873 * @param name The name of this renderer, can be null 874 */ 875 void setName(String name) { 876 nSetName(mNativeProxy, name); 877 } 878 879 /** 880 * Blocks until all previously queued work has completed. 881 */ 882 void fence() { 883 nFence(mNativeProxy); 884 } 885 886 /** 887 * Prevents any further drawing until draw() is called. This is a signal 888 * that the contents of the RenderNode tree are no longer safe to play back. 889 * In practice this usually means that there are Functor pointers in the 890 * display list that are no longer valid. 891 */ 892 void stopDrawing() { 893 nStopDrawing(mNativeProxy); 894 } 895 896 /** 897 * Called by {@link ViewRootImpl} when a new performTraverals is scheduled. 898 */ 899 public void notifyFramePending() { 900 nNotifyFramePending(mNativeProxy); 901 } 902 903 904 void registerAnimatingRenderNode(RenderNode animator) { 905 nRegisterAnimatingRenderNode(mRootNode.mNativeRenderNode, animator.mNativeRenderNode); 906 } 907 908 public void serializeDisplayListTree() { 909 nSerializeDisplayListTree(mNativeProxy); 910 } 911 912 public static boolean copySurfaceInto(Surface surface, Bitmap bitmap) { 913 return nCopySurfaceInto(surface, bitmap); 914 } 915 916 @Override 917 protected void finalize() throws Throwable { 918 try { 919 nDeleteProxy(mNativeProxy); 920 mNativeProxy = 0; 921 } finally { 922 super.finalize(); 923 } 924 } 925 926 private static class ProcessInitializer { 927 static ProcessInitializer sInstance = new ProcessInitializer(); 928 private static IBinder sProcToken; 929 930 private boolean mInitialized = false; 931 932 private ProcessInitializer() {} 933 934 synchronized void init(Context context, long renderProxy) { 935 if (mInitialized) return; 936 mInitialized = true; 937 initGraphicsStats(context, renderProxy); 938 initAssetAtlas(context, renderProxy); 939 } 940 941 private static void initGraphicsStats(Context context, long renderProxy) { 942 try { 943 IBinder binder = ServiceManager.getService("graphicsstats"); 944 if (binder == null) return; 945 IGraphicsStats graphicsStatsService = IGraphicsStats.Stub 946 .asInterface(binder); 947 sProcToken = new Binder(); 948 final String pkg = context.getApplicationInfo().packageName; 949 ParcelFileDescriptor pfd = graphicsStatsService. 950 requestBufferForProcess(pkg, sProcToken); 951 nSetProcessStatsBuffer(renderProxy, pfd.getFd()); 952 pfd.close(); 953 } catch (Throwable t) { 954 Log.w(LOG_TAG, "Could not acquire gfx stats buffer", t); 955 } 956 } 957 958 private static void initAssetAtlas(Context context, long renderProxy) { 959 IBinder binder = ServiceManager.getService("assetatlas"); 960 if (binder == null) return; 961 962 IAssetAtlas atlas = IAssetAtlas.Stub.asInterface(binder); 963 try { 964 if (atlas.isCompatible(android.os.Process.myPpid())) { 965 GraphicBuffer buffer = atlas.getBuffer(); 966 if (buffer != null) { 967 long[] map = atlas.getMap(); 968 if (map != null) { 969 nSetAtlas(renderProxy, buffer, map); 970 } 971 // If IAssetAtlas is not the same class as the IBinder 972 // we are using a remote service and we can safely 973 // destroy the graphic buffer 974 if (atlas.getClass() != binder.getClass()) { 975 buffer.destroy(); 976 } 977 } 978 } 979 } catch (RemoteException e) { 980 Log.w(LOG_TAG, "Could not acquire atlas", e); 981 } 982 } 983 } 984 985 void addFrameMetricsObserver(FrameMetricsObserver observer) { 986 long nativeObserver = nAddFrameMetricsObserver(mNativeProxy, observer); 987 observer.mNative = new VirtualRefBasePtr(nativeObserver); 988 } 989 990 void removeFrameMetricsObserver(FrameMetricsObserver observer) { 991 nRemoveFrameMetricsObserver(mNativeProxy, observer.mNative.get()); 992 observer.mNative = null; 993 } 994 995 static native void setupShadersDiskCache(String cacheFile); 996 static native void setupVulkanLayerPath(String layerPath); 997 998 private static native void nSetAtlas(long nativeProxy, GraphicBuffer buffer, long[] map); 999 private static native void nSetProcessStatsBuffer(long nativeProxy, int fd); 1000 1001 private static native long nCreateRootRenderNode(); 1002 private static native long nCreateProxy(boolean translucent, long rootRenderNode); 1003 private static native void nDeleteProxy(long nativeProxy); 1004 1005 private static native boolean nLoadSystemProperties(long nativeProxy); 1006 private static native void nSetName(long nativeProxy, String name); 1007 1008 private static native void nInitialize(long nativeProxy, Surface window); 1009 private static native void nUpdateSurface(long nativeProxy, Surface window); 1010 private static native boolean nPauseSurface(long nativeProxy, Surface window); 1011 private static native void nSetStopped(long nativeProxy, boolean stopped); 1012 private static native void nSetup(long nativeProxy, int width, int height, 1013 float lightRadius, int ambientShadowAlpha, int spotShadowAlpha); 1014 private static native void nSetLightCenter(long nativeProxy, 1015 float lightX, float lightY, float lightZ); 1016 private static native void nSetOpaque(long nativeProxy, boolean opaque); 1017 private static native int nSyncAndDrawFrame(long nativeProxy, long[] frameInfo, int size); 1018 private static native void nDestroy(long nativeProxy, long rootRenderNode); 1019 private static native void nRegisterAnimatingRenderNode(long rootRenderNode, long animatingNode); 1020 1021 private static native void nInvokeFunctor(long functor, boolean waitForCompletion); 1022 1023 private static native long nCreateTextureLayer(long nativeProxy); 1024 private static native void nBuildLayer(long nativeProxy, long node); 1025 private static native boolean nCopyLayerInto(long nativeProxy, long layer, Bitmap bitmap); 1026 private static native void nPushLayerUpdate(long nativeProxy, long layer); 1027 private static native void nCancelLayerUpdate(long nativeProxy, long layer); 1028 private static native void nDetachSurfaceTexture(long nativeProxy, long layer); 1029 1030 private static native void nDestroyHardwareResources(long nativeProxy); 1031 private static native void nTrimMemory(int level); 1032 private static native void nOverrideProperty(String name, String value); 1033 1034 private static native void nFence(long nativeProxy); 1035 private static native void nStopDrawing(long nativeProxy); 1036 private static native void nNotifyFramePending(long nativeProxy); 1037 1038 private static native void nSerializeDisplayListTree(long nativeProxy); 1039 1040 private static native void nDumpProfileInfo(long nativeProxy, FileDescriptor fd, 1041 @DumpFlags int dumpFlags); 1042 private static native void nDumpProfileData(byte[] data, FileDescriptor fd); 1043 1044 private static native void nAddRenderNode(long nativeProxy, long rootRenderNode, 1045 boolean placeFront); 1046 private static native void nRemoveRenderNode(long nativeProxy, long rootRenderNode); 1047 private static native void nDrawRenderNode(long nativeProxy, long rootRenderNode); 1048 private static native void nSetContentDrawBounds(long nativeProxy, int left, 1049 int top, int right, int bottom); 1050 1051 private static native long nAddFrameMetricsObserver(long nativeProxy, FrameMetricsObserver observer); 1052 private static native void nRemoveFrameMetricsObserver(long nativeProxy, long nativeObserver); 1053 1054 private static native boolean nCopySurfaceInto(Surface surface, Bitmap bitmap); 1055} 1056