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.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.app.ActivityManager; 22 import android.content.Context; 23 import android.content.res.TypedArray; 24 import android.graphics.BLASTBufferQueue; 25 import android.graphics.FrameInfo; 26 import android.graphics.HardwareRenderer; 27 import android.graphics.Picture; 28 import android.graphics.RecordingCanvas; 29 import android.graphics.Rect; 30 import android.graphics.RenderNode; 31 import android.os.Trace; 32 import android.util.DisplayMetrics; 33 import android.util.Log; 34 import android.view.Surface.OutOfResourcesException; 35 import android.view.View.AttachInfo; 36 import android.view.animation.AnimationUtils; 37 38 import com.android.internal.R; 39 40 import java.io.FileDescriptor; 41 import java.io.PrintWriter; 42 import java.util.ArrayList; 43 44 /** 45 * Threaded renderer that proxies the rendering to a render thread. Most calls 46 * are currently synchronous. 47 * 48 * The UI thread can block on the RenderThread, but RenderThread must never 49 * block on the UI thread. 50 * 51 * ThreadedRenderer creates an instance of RenderProxy. RenderProxy in turn creates 52 * and manages a CanvasContext on the RenderThread. The CanvasContext is fully managed 53 * by the lifecycle of the RenderProxy. 54 * 55 * Note that although currently the EGL context & surfaces are created & managed 56 * by the render thread, the goal is to move that into a shared structure that can 57 * be managed by both threads. EGLSurface creation & deletion should ideally be 58 * done on the UI thread and not the RenderThread to avoid stalling the 59 * RenderThread with surface buffer allocation. 60 * 61 * @hide 62 */ 63 public final class ThreadedRenderer extends HardwareRenderer { 64 /** 65 * System property used to enable or disable threaded rendering profiling. 66 * The default value of this property is assumed to be false. 67 * 68 * When profiling is enabled, the adb shell dumpsys gfxinfo command will 69 * output extra information about the time taken to execute by the last 70 * frames. 71 * 72 * Possible values: 73 * "true", to enable profiling 74 * "visual_bars", to enable profiling and visualize the results on screen 75 * "false", to disable profiling 76 * 77 * @see #PROFILE_PROPERTY_VISUALIZE_BARS 78 * 79 * @hide 80 */ 81 public static final String PROFILE_PROPERTY = "debug.hwui.profile"; 82 83 /** 84 * Value for {@link #PROFILE_PROPERTY}. When the property is set to this 85 * value, profiling data will be visualized on screen as a bar chart. 86 * 87 * @hide 88 */ 89 public static final String PROFILE_PROPERTY_VISUALIZE_BARS = "visual_bars"; 90 91 /** 92 * System property used to specify the number of frames to be used 93 * when doing threaded rendering profiling. 94 * The default value of this property is #PROFILE_MAX_FRAMES. 95 * 96 * When profiling is enabled, the adb shell dumpsys gfxinfo command will 97 * output extra information about the time taken to execute by the last 98 * frames. 99 * 100 * Possible values: 101 * "60", to set the limit of frames to 60 102 */ 103 static final String PROFILE_MAXFRAMES_PROPERTY = "debug.hwui.profile.maxframes"; 104 105 /** 106 * System property used to debug EGL configuration choice. 107 * 108 * Possible values: 109 * "choice", print the chosen configuration only 110 * "all", print all possible configurations 111 */ 112 static final String PRINT_CONFIG_PROPERTY = "debug.hwui.print_config"; 113 114 /** 115 * Turn on to draw dirty regions every other frame. 116 * 117 * Possible values: 118 * "true", to enable dirty regions debugging 119 * "false", to disable dirty regions debugging 120 * 121 * @hide 122 */ 123 public static final String DEBUG_DIRTY_REGIONS_PROPERTY = "debug.hwui.show_dirty_regions"; 124 125 /** 126 * Turn on to flash hardware layers when they update. 127 * 128 * Possible values: 129 * "true", to enable hardware layers updates debugging 130 * "false", to disable hardware layers updates debugging 131 * 132 * @hide 133 */ 134 public static final String DEBUG_SHOW_LAYERS_UPDATES_PROPERTY = 135 "debug.hwui.show_layers_updates"; 136 137 /** 138 * Controls overdraw debugging. 139 * 140 * Possible values: 141 * "false", to disable overdraw debugging 142 * "show", to show overdraw areas on screen 143 * "count", to display an overdraw counter 144 * 145 * @hide 146 */ 147 public static final String DEBUG_OVERDRAW_PROPERTY = "debug.hwui.overdraw"; 148 149 /** 150 * Value for {@link #DEBUG_OVERDRAW_PROPERTY}. When the property is set to this 151 * value, overdraw will be shown on screen by coloring pixels. 152 * 153 * @hide 154 */ 155 public static final String OVERDRAW_PROPERTY_SHOW = "show"; 156 157 /** 158 * Turn on to debug non-rectangular clip operations. 159 * 160 * Possible values: 161 * "hide", to disable this debug mode 162 * "highlight", highlight drawing commands tested against a non-rectangular clip 163 * "stencil", renders the clip region on screen when set 164 * 165 * @hide 166 */ 167 public static final String DEBUG_SHOW_NON_RECTANGULAR_CLIP_PROPERTY = 168 "debug.hwui.show_non_rect_clip"; 169 170 /** 171 * Sets the FPS devisor to lower the FPS. 172 * 173 * Sets a positive integer as a divisor. 1 (the default value) menas the full FPS, and 2 174 * means half the full FPS. 175 * 176 * 177 * @hide 178 */ 179 public static final String DEBUG_FPS_DIVISOR = "debug.hwui.fps_divisor"; 180 181 /** 182 * Forces smart-dark to be always on. 183 * @hide 184 */ 185 public static final String DEBUG_FORCE_DARK = "debug.hwui.force_dark"; 186 187 public static int EGL_CONTEXT_PRIORITY_REALTIME_NV = 0x3357; 188 public static int EGL_CONTEXT_PRIORITY_HIGH_IMG = 0x3101; 189 public static int EGL_CONTEXT_PRIORITY_MEDIUM_IMG = 0x3102; 190 public static int EGL_CONTEXT_PRIORITY_LOW_IMG = 0x3103; 191 192 /** 193 * Further threaded renderer disabling for the system process. 194 * 195 * @hide 196 */ 197 public static boolean sRendererEnabled = true; 198 199 /** 200 * Controls whether or not the renderer should aggressively trim 201 * memory. Note that this must not be set for any process that uses 202 * WebView! This should be only used by system_process or similar 203 * that do not go into the background. 204 */ enableForegroundTrimming()205 public static void enableForegroundTrimming() { 206 // TODO: Remove 207 } 208 209 210 /** 211 * Initialize HWUI for being in a system process like system_server 212 * Should not be called in non-system processes 213 */ initForSystemProcess()214 public static void initForSystemProcess() { 215 // The system process on low-memory devices do not get to use hardware 216 // accelerated drawing, since this can add too much overhead to the 217 // process. 218 if (!ActivityManager.isHighEndGfx()) { 219 sRendererEnabled = false; 220 } 221 setIsSystemOrPersistent(); 222 } 223 224 /** 225 * Creates a threaded renderer using OpenGL. 226 * 227 * @param translucent True if the surface is translucent, false otherwise 228 * 229 * @return A threaded renderer backed by OpenGL. 230 */ create(Context context, boolean translucent, String name)231 public static ThreadedRenderer create(Context context, boolean translucent, String name) { 232 return new ThreadedRenderer(context, translucent, name); 233 } 234 235 private static final String[] VISUALIZERS = { 236 PROFILE_PROPERTY_VISUALIZE_BARS, 237 }; 238 239 // Size of the rendered content. 240 private int mWidth, mHeight; 241 242 // Actual size of the drawing surface. 243 private int mSurfaceWidth, mSurfaceHeight; 244 245 // Insets between the drawing surface and rendered content. These are 246 // applied as translation when updating the root render node. 247 private int mInsetTop, mInsetLeft; 248 249 // Light properties specified by the theme. 250 private final float mLightY; 251 private final float mLightZ; 252 private final float mLightRadius; 253 254 private boolean mInitialized = false; 255 private boolean mRootNodeNeedsUpdate; 256 257 private boolean mEnabled; 258 private boolean mRequested = true; 259 260 /** 261 * This child class exists to break ownership cycles. ViewRootImpl owns a ThreadedRenderer 262 * which owns a WebViewOverlayProvider. WebViewOverlayProvider will in turn be set as 263 * the listener for HardwareRenderer callbacks. By keeping this a child class, there are 264 * no cycles in the chain. The ThreadedRenderer will remain GC-able if any callbacks are 265 * still outstanding, which will in turn release any JNI references to WebViewOverlayProvider. 266 */ 267 private static final class WebViewOverlayProvider implements 268 PrepareSurfaceControlForWebviewCallback, ASurfaceTransactionCallback { 269 private static final boolean sOverlaysAreEnabled = 270 HardwareRenderer.isWebViewOverlaysEnabled(); 271 private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction(); 272 private boolean mHasWebViewOverlays = false; 273 private BLASTBufferQueue mBLASTBufferQueue; 274 private SurfaceControl mSurfaceControl; 275 setSurfaceControlOpaque(boolean opaque)276 public boolean setSurfaceControlOpaque(boolean opaque) { 277 synchronized (this) { 278 if (mHasWebViewOverlays) return false; 279 mTransaction.setOpaque(mSurfaceControl, opaque).apply(); 280 } 281 return opaque; 282 } 283 shouldEnableOverlaySupport()284 public boolean shouldEnableOverlaySupport() { 285 return sOverlaysAreEnabled && mSurfaceControl != null && mBLASTBufferQueue != null; 286 } 287 setSurfaceControl(SurfaceControl surfaceControl)288 public void setSurfaceControl(SurfaceControl surfaceControl) { 289 synchronized (this) { 290 mSurfaceControl = surfaceControl; 291 if (mSurfaceControl != null && mHasWebViewOverlays) { 292 mTransaction.setOpaque(surfaceControl, false).apply(); 293 } 294 } 295 } 296 setBLASTBufferQueue(BLASTBufferQueue bufferQueue)297 public void setBLASTBufferQueue(BLASTBufferQueue bufferQueue) { 298 synchronized (this) { 299 mBLASTBufferQueue = bufferQueue; 300 } 301 } 302 303 @Override prepare()304 public void prepare() { 305 synchronized (this) { 306 mHasWebViewOverlays = true; 307 if (mSurfaceControl != null) { 308 mTransaction.setOpaque(mSurfaceControl, false).apply(); 309 } 310 } 311 } 312 313 @Override onMergeTransaction(long nativeTransactionObj, long aSurfaceControlNativeObj, long frameNr)314 public boolean onMergeTransaction(long nativeTransactionObj, 315 long aSurfaceControlNativeObj, long frameNr) { 316 synchronized (this) { 317 if (mBLASTBufferQueue == null) { 318 return false; 319 } else { 320 mBLASTBufferQueue.mergeWithNextTransaction(nativeTransactionObj, frameNr); 321 return true; 322 } 323 } 324 } 325 } 326 327 private final WebViewOverlayProvider mWebViewOverlayProvider = new WebViewOverlayProvider(); 328 private boolean mWebViewOverlaysEnabled = false; 329 330 @Nullable 331 private ArrayList<FrameDrawingCallback> mNextRtFrameCallbacks; 332 ThreadedRenderer(Context context, boolean translucent, String name)333 ThreadedRenderer(Context context, boolean translucent, String name) { 334 super(); 335 setName(name); 336 setOpaque(!translucent); 337 338 final TypedArray a = context.obtainStyledAttributes(null, R.styleable.Lighting, 0, 0); 339 mLightY = a.getDimension(R.styleable.Lighting_lightY, 0); 340 mLightZ = a.getDimension(R.styleable.Lighting_lightZ, 0); 341 mLightRadius = a.getDimension(R.styleable.Lighting_lightRadius, 0); 342 float ambientShadowAlpha = a.getFloat(R.styleable.Lighting_ambientShadowAlpha, 0); 343 float spotShadowAlpha = a.getFloat(R.styleable.Lighting_spotShadowAlpha, 0); 344 a.recycle(); 345 setLightSourceAlpha(ambientShadowAlpha, spotShadowAlpha); 346 } 347 348 @Override destroy()349 public void destroy() { 350 mInitialized = false; 351 updateEnabledState(null); 352 super.destroy(); 353 } 354 355 /** 356 * Indicates whether threaded rendering is currently enabled. 357 * 358 * @return True if threaded rendering is in use, false otherwise. 359 */ isEnabled()360 boolean isEnabled() { 361 return mEnabled; 362 } 363 364 /** 365 * Indicates whether threaded rendering is currently enabled. 366 * 367 * @param enabled True if the threaded renderer is in use, false otherwise. 368 */ setEnabled(boolean enabled)369 void setEnabled(boolean enabled) { 370 mEnabled = enabled; 371 } 372 373 /** 374 * Indicates whether threaded rendering is currently request but not 375 * necessarily enabled yet. 376 * 377 * @return True if requested, false otherwise. 378 */ isRequested()379 boolean isRequested() { 380 return mRequested; 381 } 382 383 /** 384 * Indicates whether threaded rendering is currently requested but not 385 * necessarily enabled yet. 386 */ setRequested(boolean requested)387 void setRequested(boolean requested) { 388 mRequested = requested; 389 } 390 updateEnabledState(Surface surface)391 private void updateEnabledState(Surface surface) { 392 if (surface == null || !surface.isValid()) { 393 setEnabled(false); 394 } else { 395 setEnabled(mInitialized); 396 } 397 } 398 399 /** 400 * Initializes the threaded renderer for the specified surface. 401 * 402 * @param surface The surface to render 403 * 404 * @return True if the initialization was successful, false otherwise. 405 */ initialize(Surface surface)406 boolean initialize(Surface surface) throws OutOfResourcesException { 407 boolean status = !mInitialized; 408 mInitialized = true; 409 updateEnabledState(surface); 410 setSurface(surface); 411 return status; 412 } 413 414 /** 415 * Initializes the threaded renderer for the specified surface and setup the 416 * renderer for drawing, if needed. This is invoked when the ViewAncestor has 417 * potentially lost the threaded renderer. The threaded renderer should be 418 * reinitialized and setup when the render {@link #isRequested()} and 419 * {@link #isEnabled()}. 420 * 421 * @param width The width of the drawing surface. 422 * @param height The height of the drawing surface. 423 * @param attachInfo Information about the window. 424 * @param surface The surface to render 425 * @param surfaceInsets The drawing surface insets to apply 426 * 427 * @return true if the surface was initialized, false otherwise. Returning 428 * false might mean that the surface was already initialized. 429 */ initializeIfNeeded(int width, int height, View.AttachInfo attachInfo, Surface surface, Rect surfaceInsets)430 boolean initializeIfNeeded(int width, int height, View.AttachInfo attachInfo, 431 Surface surface, Rect surfaceInsets) throws OutOfResourcesException { 432 if (isRequested()) { 433 // We lost the gl context, so recreate it. 434 if (!isEnabled()) { 435 if (initialize(surface)) { 436 setup(width, height, attachInfo, surfaceInsets); 437 return true; 438 } 439 } 440 } 441 return false; 442 } 443 444 /** 445 * Updates the threaded renderer for the specified surface. 446 * 447 * @param surface The surface to render 448 */ updateSurface(Surface surface)449 void updateSurface(Surface surface) throws OutOfResourcesException { 450 updateEnabledState(surface); 451 setSurface(surface); 452 } 453 454 @Override setSurface(Surface surface)455 public void setSurface(Surface surface) { 456 // TODO: Do we ever pass a non-null but isValid() = false surface? 457 // This is here to be super conservative for ViewRootImpl 458 if (surface != null && surface.isValid()) { 459 super.setSurface(surface); 460 } else { 461 super.setSurface(null); 462 } 463 } 464 465 /** 466 * Registers a callback to be executed when the next frame is being drawn on RenderThread. This 467 * callback will be executed on a RenderThread worker thread, and only used for the next frame 468 * and thus it will only fire once. 469 * 470 * @param callback The callback to register. 471 */ registerRtFrameCallback(@onNull FrameDrawingCallback callback)472 void registerRtFrameCallback(@NonNull FrameDrawingCallback callback) { 473 if (mNextRtFrameCallbacks == null) { 474 mNextRtFrameCallbacks = new ArrayList<>(); 475 } 476 mNextRtFrameCallbacks.add(callback); 477 } 478 479 /** 480 * Remove a frame drawing callback that was added via 481 * {@link #registerRtFrameCallback(FrameDrawingCallback)} 482 * 483 * @param callback The callback to unregister. 484 */ unregisterRtFrameCallback(@onNull FrameDrawingCallback callback)485 void unregisterRtFrameCallback(@NonNull FrameDrawingCallback callback) { 486 if (mNextRtFrameCallbacks == null) { 487 return; 488 } 489 mNextRtFrameCallbacks.remove(callback); 490 } 491 492 /** 493 * Destroys all hardware rendering resources associated with the specified 494 * view hierarchy. 495 * 496 * @param view The root of the view hierarchy 497 */ destroyHardwareResources(View view)498 void destroyHardwareResources(View view) { 499 destroyResources(view); 500 clearContent(); 501 } 502 destroyResources(View view)503 private static void destroyResources(View view) { 504 view.destroyHardwareResources(); 505 } 506 507 /** 508 * Sets up the renderer for drawing. 509 * 510 * @param width The width of the drawing surface. 511 * @param height The height of the drawing surface. 512 * @param attachInfo Information about the window. 513 * @param surfaceInsets The drawing surface insets to apply 514 */ setup(int width, int height, AttachInfo attachInfo, Rect surfaceInsets)515 void setup(int width, int height, AttachInfo attachInfo, Rect surfaceInsets) { 516 mWidth = width; 517 mHeight = height; 518 519 if (surfaceInsets != null && (surfaceInsets.left != 0 || surfaceInsets.right != 0 520 || surfaceInsets.top != 0 || surfaceInsets.bottom != 0)) { 521 mInsetLeft = surfaceInsets.left; 522 mInsetTop = surfaceInsets.top; 523 mSurfaceWidth = width + mInsetLeft + surfaceInsets.right; 524 mSurfaceHeight = height + mInsetTop + surfaceInsets.bottom; 525 526 // If the surface has insets, it can't be opaque. 527 setOpaque(false); 528 } else { 529 mInsetLeft = 0; 530 mInsetTop = 0; 531 mSurfaceWidth = width; 532 mSurfaceHeight = height; 533 } 534 535 mRootNode.setLeftTopRightBottom(-mInsetLeft, -mInsetTop, mSurfaceWidth, mSurfaceHeight); 536 537 setLightCenter(attachInfo); 538 } 539 540 /** 541 * Whether or not the renderer owns the SurfaceControl's opacity. If true, use 542 * {@link #setSurfaceControlOpaque(boolean)} to update the opacity 543 */ rendererOwnsSurfaceControlOpacity()544 public boolean rendererOwnsSurfaceControlOpacity() { 545 return mWebViewOverlayProvider.mSurfaceControl != null; 546 } 547 548 /** 549 * Sets the SurfaceControl's opacity that this HardwareRenderer is rendering onto. The renderer 550 * may opt to override the opacity, and will return the value that is ultimately set 551 * 552 * @return true if the surface is opaque, false otherwise 553 * 554 * @hide 555 */ setSurfaceControlOpaque(boolean opaque)556 public boolean setSurfaceControlOpaque(boolean opaque) { 557 return mWebViewOverlayProvider.setSurfaceControlOpaque(opaque); 558 } 559 updateWebViewOverlayCallbacks()560 private void updateWebViewOverlayCallbacks() { 561 boolean shouldEnable = mWebViewOverlayProvider.shouldEnableOverlaySupport(); 562 if (shouldEnable != mWebViewOverlaysEnabled) { 563 mWebViewOverlaysEnabled = shouldEnable; 564 if (shouldEnable) { 565 setASurfaceTransactionCallback(mWebViewOverlayProvider); 566 setPrepareSurfaceControlForWebviewCallback(mWebViewOverlayProvider); 567 } else { 568 setASurfaceTransactionCallback(null); 569 setPrepareSurfaceControlForWebviewCallback(null); 570 } 571 } 572 } 573 574 @Override setSurfaceControl(@ullable SurfaceControl surfaceControl, @Nullable BLASTBufferQueue blastBufferQueue)575 public void setSurfaceControl(@Nullable SurfaceControl surfaceControl, 576 @Nullable BLASTBufferQueue blastBufferQueue) { 577 super.setSurfaceControl(surfaceControl, blastBufferQueue); 578 mWebViewOverlayProvider.setSurfaceControl(surfaceControl); 579 mWebViewOverlayProvider.setBLASTBufferQueue(blastBufferQueue); 580 updateWebViewOverlayCallbacks(); 581 } 582 583 @Override notifyCallbackPending()584 public void notifyCallbackPending() { 585 if (isEnabled()) { 586 super.notifyCallbackPending(); 587 } 588 } 589 590 @Override notifyExpensiveFrame()591 public void notifyExpensiveFrame() { 592 if (isEnabled()) { 593 super.notifyExpensiveFrame(); 594 } 595 } 596 597 /** 598 * Updates the light position based on the position of the window. 599 * 600 * @param attachInfo Information about the window. 601 */ setLightCenter(AttachInfo attachInfo)602 void setLightCenter(AttachInfo attachInfo) { 603 // Adjust light position for window offsets. 604 DisplayMetrics displayMetrics = new DisplayMetrics(); 605 attachInfo.mDisplay.getRealMetrics(displayMetrics); 606 final float lightX = displayMetrics.widthPixels / 2f - attachInfo.mWindowLeft; 607 final float lightY = mLightY - attachInfo.mWindowTop; 608 // To prevent shadow distortion on larger screens, scale the z position of the light source 609 // relative to the smallest screen dimension. 610 final float zRatio = Math.min(displayMetrics.widthPixels, displayMetrics.heightPixels) 611 / (450f * displayMetrics.density); 612 final float zWeightedAdjustment = (zRatio + 2) / 3f; 613 final float lightZ = mLightZ * zWeightedAdjustment; 614 615 setLightSourceGeometry(lightX, lightY, lightZ, mLightRadius); 616 } 617 618 /** 619 * Gets the current width of the surface. This is the width that the surface 620 * was last set to in a call to {@link #setup(int, int, View.AttachInfo, Rect)}. 621 * 622 * @return the current width of the surface 623 */ getWidth()624 int getWidth() { 625 return mWidth; 626 } 627 628 /** 629 * Gets the current height of the surface. This is the height that the surface 630 * was last set to in a call to {@link #setup(int, int, View.AttachInfo, Rect)}. 631 * 632 * @return the current width of the surface 633 */ getHeight()634 int getHeight() { 635 return mHeight; 636 } 637 dumpArgsToFlags(String[] args)638 private static int dumpArgsToFlags(String[] args) { 639 // If there's no arguments, eg 'dumpsys gfxinfo', then dump everything. 640 // If there's a targetted package, eg 'dumpsys gfxinfo com.android.systemui', then only 641 // dump the summary information 642 if (args == null || args.length == 0) { 643 return FLAG_DUMP_ALL; 644 } 645 int flags = 0; 646 for (int i = 0; i < args.length; i++) { 647 switch (args[i]) { 648 case "framestats": 649 flags |= FLAG_DUMP_FRAMESTATS; 650 break; 651 case "reset": 652 flags |= FLAG_DUMP_RESET; 653 break; 654 case "-a": // magic option passed when dumping a bugreport. 655 flags = FLAG_DUMP_ALL; 656 break; 657 } 658 } 659 return flags; 660 } 661 662 /** @hide */ handleDumpGfxInfo(FileDescriptor fd, String[] args)663 public static void handleDumpGfxInfo(FileDescriptor fd, String[] args) { 664 dumpGlobalProfileInfo(fd, dumpArgsToFlags(args)); 665 WindowManagerGlobal.getInstance().dumpGfxInfo(fd, args); 666 } 667 668 /** 669 * Outputs extra debugging information in the specified file descriptor. 670 */ dumpGfxInfo(PrintWriter pw, FileDescriptor fd, String[] args)671 void dumpGfxInfo(PrintWriter pw, FileDescriptor fd, String[] args) { 672 pw.flush(); 673 dumpProfileInfo(fd, dumpArgsToFlags(args)); 674 } 675 captureRenderingCommands()676 Picture captureRenderingCommands() { 677 return null; 678 } 679 680 @Override loadSystemProperties()681 public boolean loadSystemProperties() { 682 boolean changed = super.loadSystemProperties(); 683 if (changed) { 684 invalidateRoot(); 685 } 686 return changed; 687 } 688 updateViewTreeDisplayList(View view)689 private void updateViewTreeDisplayList(View view) { 690 view.mPrivateFlags |= View.PFLAG_DRAWN; 691 view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED) 692 == View.PFLAG_INVALIDATED; 693 view.mPrivateFlags &= ~View.PFLAG_INVALIDATED; 694 view.updateDisplayListIfDirty(); 695 view.mRecreateDisplayList = false; 696 } 697 updateRootDisplayList(View view, DrawCallbacks callbacks)698 private void updateRootDisplayList(View view, DrawCallbacks callbacks) { 699 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Record View#draw()"); 700 updateViewTreeDisplayList(view); 701 702 // Consume and set the frame callback after we dispatch draw to the view above, but before 703 // onPostDraw below which may reset the callback for the next frame. This ensures that 704 // updates to the frame callback during scroll handling will also apply in this frame. 705 if (mNextRtFrameCallbacks != null) { 706 final ArrayList<FrameDrawingCallback> frameCallbacks = mNextRtFrameCallbacks; 707 mNextRtFrameCallbacks = null; 708 setFrameCallback(new FrameDrawingCallback() { 709 @Override 710 public void onFrameDraw(long frame) { 711 } 712 713 @Override 714 public FrameCommitCallback onFrameDraw(int syncResult, long frame) { 715 ArrayList<FrameCommitCallback> frameCommitCallbacks = new ArrayList<>(); 716 for (int i = 0; i < frameCallbacks.size(); ++i) { 717 FrameCommitCallback frameCommitCallback = frameCallbacks.get(i) 718 .onFrameDraw(syncResult, frame); 719 if (frameCommitCallback != null) { 720 frameCommitCallbacks.add(frameCommitCallback); 721 } 722 } 723 724 if (frameCommitCallbacks.isEmpty()) { 725 return null; 726 } 727 728 return didProduceBuffer -> { 729 for (int i = 0; i < frameCommitCallbacks.size(); ++i) { 730 frameCommitCallbacks.get(i).onFrameCommit(didProduceBuffer); 731 } 732 }; 733 } 734 }); 735 } 736 737 if (mRootNodeNeedsUpdate || !mRootNode.hasDisplayList()) { 738 RecordingCanvas canvas = mRootNode.beginRecording(mSurfaceWidth, mSurfaceHeight); 739 try { 740 final int saveCount = canvas.save(); 741 canvas.translate(mInsetLeft, mInsetTop); 742 callbacks.onPreDraw(canvas); 743 744 canvas.enableZ(); 745 canvas.drawRenderNode(view.updateDisplayListIfDirty()); 746 canvas.disableZ(); 747 748 callbacks.onPostDraw(canvas); 749 canvas.restoreToCount(saveCount); 750 mRootNodeNeedsUpdate = false; 751 } finally { 752 mRootNode.endRecording(); 753 } 754 } 755 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 756 } 757 758 /** 759 * Interface used to receive callbacks whenever a view is drawn by 760 * a threaded renderer instance. 761 */ 762 interface DrawCallbacks { 763 /** 764 * Invoked before a view is drawn by a threaded renderer. 765 * This method can be used to apply transformations to the 766 * canvas but no drawing command should be issued. 767 * 768 * @param canvas The Canvas used to render the view. 769 */ onPreDraw(RecordingCanvas canvas)770 void onPreDraw(RecordingCanvas canvas); 771 772 /** 773 * Invoked after a view is drawn by a threaded renderer. 774 * It is safe to invoke drawing commands from this method. 775 * 776 * @param canvas The Canvas used to render the view. 777 */ onPostDraw(RecordingCanvas canvas)778 void onPostDraw(RecordingCanvas canvas); 779 } 780 781 /** 782 * Indicates that the content drawn by DrawCallbacks needs to 783 * be updated, which will be done by the next call to draw() 784 */ invalidateRoot()785 void invalidateRoot() { 786 mRootNodeNeedsUpdate = true; 787 } 788 789 /** 790 * Draws the specified view. 791 * 792 * @param view The view to draw. 793 * @param attachInfo AttachInfo tied to the specified view. 794 */ draw(View view, AttachInfo attachInfo, DrawCallbacks callbacks)795 void draw(View view, AttachInfo attachInfo, DrawCallbacks callbacks) { 796 attachInfo.mViewRootImpl.mViewFrameInfo.markDrawStart(); 797 798 updateRootDisplayList(view, callbacks); 799 800 // register animating rendernodes which started animating prior to renderer 801 // creation, which is typical for animators started prior to first draw 802 if (attachInfo.mPendingAnimatingRenderNodes != null) { 803 final int count = attachInfo.mPendingAnimatingRenderNodes.size(); 804 for (int i = 0; i < count; i++) { 805 registerAnimatingRenderNode( 806 attachInfo.mPendingAnimatingRenderNodes.get(i)); 807 } 808 attachInfo.mPendingAnimatingRenderNodes.clear(); 809 // We don't need this anymore as subsequent calls to 810 // ViewRootImpl#attachRenderNodeAnimator will go directly to us. 811 attachInfo.mPendingAnimatingRenderNodes = null; 812 } 813 814 final FrameInfo frameInfo = attachInfo.mViewRootImpl.getUpdatedFrameInfo(); 815 816 int syncResult = syncAndDrawFrame(frameInfo); 817 if ((syncResult & SYNC_LOST_SURFACE_REWARD_IF_FOUND) != 0) { 818 Log.w("HWUI", "Surface lost, forcing relayout"); 819 // We lost our surface. For a relayout next frame which should give us a new 820 // surface from WindowManager, which hopefully will work. 821 attachInfo.mViewRootImpl.mForceNextWindowRelayout = true; 822 attachInfo.mViewRootImpl.requestLayout(); 823 } 824 if ((syncResult & SYNC_REDRAW_REQUESTED) != 0) { 825 attachInfo.mViewRootImpl.invalidate(); 826 } 827 } 828 829 /** The root of everything */ getRootNode()830 public @NonNull RenderNode getRootNode() { 831 return mRootNode; 832 } 833 834 /** 835 * Basic synchronous renderer. Currently only used to render the Magnifier, so use with care. 836 * TODO: deduplicate against ThreadedRenderer. 837 * 838 * @hide 839 */ 840 public static class SimpleRenderer extends HardwareRenderer { 841 private final float mLightY, mLightZ, mLightRadius; 842 SimpleRenderer(final Context context, final String name, final Surface surface)843 public SimpleRenderer(final Context context, final String name, final Surface surface) { 844 super(); 845 setName(name); 846 setOpaque(false); 847 setSurface(surface); 848 final TypedArray a = context.obtainStyledAttributes(null, R.styleable.Lighting, 0, 0); 849 mLightY = a.getDimension(R.styleable.Lighting_lightY, 0); 850 mLightZ = a.getDimension(R.styleable.Lighting_lightZ, 0); 851 mLightRadius = a.getDimension(R.styleable.Lighting_lightRadius, 0); 852 final float ambientShadowAlpha = a.getFloat(R.styleable.Lighting_ambientShadowAlpha, 0); 853 final float spotShadowAlpha = a.getFloat(R.styleable.Lighting_spotShadowAlpha, 0); 854 a.recycle(); 855 setLightSourceAlpha(ambientShadowAlpha, spotShadowAlpha); 856 } 857 858 /** 859 * Set the light center. 860 */ setLightCenter(final Display display, final int windowLeft, final int windowTop)861 public void setLightCenter(final Display display, 862 final int windowLeft, final int windowTop) { 863 // Adjust light position for window offsets. 864 DisplayMetrics displayMetrics = new DisplayMetrics(); 865 display.getRealMetrics(displayMetrics); 866 final float lightX = displayMetrics.widthPixels / 2f - windowLeft; 867 final float lightY = mLightY - windowTop; 868 // To prevent shadow distortion on larger screens, scale the z position of the light 869 // source relative to the smallest screen dimension. 870 final float zRatio = Math.min(displayMetrics.widthPixels, displayMetrics.heightPixels) 871 / (450f * displayMetrics.density); 872 final float zWeightedAdjustment = (zRatio + 2) / 3f; 873 final float lightZ = mLightZ * zWeightedAdjustment; 874 875 setLightSourceGeometry(lightX, lightY, lightZ, mLightRadius); 876 } 877 getRootNode()878 public RenderNode getRootNode() { 879 return mRootNode; 880 } 881 882 /** 883 * Draw the surface. 884 */ draw(final FrameDrawingCallback callback)885 public void draw(final FrameDrawingCallback callback) { 886 final long vsync = AnimationUtils.currentAnimationTimeMillis() * 1000000L; 887 if (callback != null) { 888 setFrameCallback(callback); 889 } 890 createRenderRequest() 891 .setVsyncTime(vsync) 892 .syncAndDraw(); 893 } 894 } 895 } 896