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 public static boolean sTrimForeground = false; 200 201 /** 202 * Controls whether or not the renderer should aggressively trim 203 * memory. Note that this must not be set for any process that uses 204 * WebView! This should be only used by system_process or similar 205 * that do not go into the background. 206 */ enableForegroundTrimming()207 public static void enableForegroundTrimming() { 208 sTrimForeground = true; 209 } 210 211 /** 212 * Initialize HWUI for being in a system process like system_server 213 * Should not be called in non-system processes 214 */ initForSystemProcess()215 public static void initForSystemProcess() { 216 // The system process on low-memory devices do not get to use hardware 217 // accelerated drawing, since this can add too much overhead to the 218 // process. 219 if (!ActivityManager.isHighEndGfx()) { 220 sRendererEnabled = false; 221 } else { 222 enableForegroundTrimming(); 223 } 224 } 225 226 /** 227 * Creates a threaded renderer using OpenGL. 228 * 229 * @param translucent True if the surface is translucent, false otherwise 230 * 231 * @return A threaded renderer backed by OpenGL. 232 */ create(Context context, boolean translucent, String name)233 public static ThreadedRenderer create(Context context, boolean translucent, String name) { 234 return new ThreadedRenderer(context, translucent, name); 235 } 236 237 private static final String[] VISUALIZERS = { 238 PROFILE_PROPERTY_VISUALIZE_BARS, 239 }; 240 241 // Size of the rendered content. 242 private int mWidth, mHeight; 243 244 // Actual size of the drawing surface. 245 private int mSurfaceWidth, mSurfaceHeight; 246 247 // Insets between the drawing surface and rendered content. These are 248 // applied as translation when updating the root render node. 249 private int mInsetTop, mInsetLeft; 250 251 // Light properties specified by the theme. 252 private final float mLightY; 253 private final float mLightZ; 254 private final float mLightRadius; 255 256 private boolean mInitialized = false; 257 private boolean mRootNodeNeedsUpdate; 258 259 private boolean mEnabled; 260 private boolean mRequested = true; 261 262 /** 263 * This child class exists to break ownership cycles. ViewRootImpl owns a ThreadedRenderer 264 * which owns a WebViewOverlayProvider. WebViewOverlayProvider will in turn be set as 265 * the listener for HardwareRenderer callbacks. By keeping this a child class, there are 266 * no cycles in the chain. The ThreadedRenderer will remain GC-able if any callbacks are 267 * still outstanding, which will in turn release any JNI references to WebViewOverlayProvider. 268 */ 269 private static final class WebViewOverlayProvider implements 270 PrepareSurfaceControlForWebviewCallback, ASurfaceTransactionCallback { 271 private static final boolean sOverlaysAreEnabled = 272 HardwareRenderer.isWebViewOverlaysEnabled(); 273 private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction(); 274 private boolean mHasWebViewOverlays = false; 275 private BLASTBufferQueue mBLASTBufferQueue; 276 private SurfaceControl mSurfaceControl; 277 setSurfaceControlOpaque(boolean opaque)278 public boolean setSurfaceControlOpaque(boolean opaque) { 279 synchronized (this) { 280 if (mHasWebViewOverlays) return false; 281 mTransaction.setOpaque(mSurfaceControl, opaque).apply(); 282 } 283 return opaque; 284 } 285 shouldEnableOverlaySupport()286 public boolean shouldEnableOverlaySupport() { 287 return sOverlaysAreEnabled && mSurfaceControl != null && mBLASTBufferQueue != null; 288 } 289 setSurfaceControl(SurfaceControl surfaceControl)290 public void setSurfaceControl(SurfaceControl surfaceControl) { 291 synchronized (this) { 292 mSurfaceControl = surfaceControl; 293 if (mSurfaceControl != null && mHasWebViewOverlays) { 294 mTransaction.setOpaque(surfaceControl, false).apply(); 295 } 296 } 297 } 298 setBLASTBufferQueue(BLASTBufferQueue bufferQueue)299 public void setBLASTBufferQueue(BLASTBufferQueue bufferQueue) { 300 synchronized (this) { 301 mBLASTBufferQueue = bufferQueue; 302 } 303 } 304 305 @Override prepare()306 public void prepare() { 307 synchronized (this) { 308 mHasWebViewOverlays = true; 309 if (mSurfaceControl != null) { 310 mTransaction.setOpaque(mSurfaceControl, false).apply(); 311 } 312 } 313 } 314 315 @Override onMergeTransaction(long nativeTransactionObj, long aSurfaceControlNativeObj, long frameNr)316 public boolean onMergeTransaction(long nativeTransactionObj, 317 long aSurfaceControlNativeObj, long frameNr) { 318 synchronized (this) { 319 if (mBLASTBufferQueue == null) { 320 return false; 321 } else { 322 mBLASTBufferQueue.mergeWithNextTransaction(nativeTransactionObj, frameNr); 323 return true; 324 } 325 } 326 } 327 } 328 329 private final WebViewOverlayProvider mWebViewOverlayProvider = new WebViewOverlayProvider(); 330 private boolean mWebViewOverlaysEnabled = false; 331 332 @Nullable 333 private ArrayList<FrameDrawingCallback> mNextRtFrameCallbacks; 334 ThreadedRenderer(Context context, boolean translucent, String name)335 ThreadedRenderer(Context context, boolean translucent, String name) { 336 super(); 337 setName(name); 338 setOpaque(!translucent); 339 340 final TypedArray a = context.obtainStyledAttributes(null, R.styleable.Lighting, 0, 0); 341 mLightY = a.getDimension(R.styleable.Lighting_lightY, 0); 342 mLightZ = a.getDimension(R.styleable.Lighting_lightZ, 0); 343 mLightRadius = a.getDimension(R.styleable.Lighting_lightRadius, 0); 344 float ambientShadowAlpha = a.getFloat(R.styleable.Lighting_ambientShadowAlpha, 0); 345 float spotShadowAlpha = a.getFloat(R.styleable.Lighting_spotShadowAlpha, 0); 346 a.recycle(); 347 setLightSourceAlpha(ambientShadowAlpha, spotShadowAlpha); 348 } 349 350 @Override destroy()351 public void destroy() { 352 mInitialized = false; 353 updateEnabledState(null); 354 super.destroy(); 355 } 356 357 /** 358 * Indicates whether threaded rendering is currently enabled. 359 * 360 * @return True if threaded rendering is in use, false otherwise. 361 */ isEnabled()362 boolean isEnabled() { 363 return mEnabled; 364 } 365 366 /** 367 * Indicates whether threaded rendering is currently enabled. 368 * 369 * @param enabled True if the threaded renderer is in use, false otherwise. 370 */ setEnabled(boolean enabled)371 void setEnabled(boolean enabled) { 372 mEnabled = enabled; 373 } 374 375 /** 376 * Indicates whether threaded rendering is currently request but not 377 * necessarily enabled yet. 378 * 379 * @return True if requested, false otherwise. 380 */ isRequested()381 boolean isRequested() { 382 return mRequested; 383 } 384 385 /** 386 * Indicates whether threaded rendering is currently requested but not 387 * necessarily enabled yet. 388 */ setRequested(boolean requested)389 void setRequested(boolean requested) { 390 mRequested = requested; 391 } 392 updateEnabledState(Surface surface)393 private void updateEnabledState(Surface surface) { 394 if (surface == null || !surface.isValid()) { 395 setEnabled(false); 396 } else { 397 setEnabled(mInitialized); 398 } 399 } 400 401 /** 402 * Initializes the threaded renderer for the specified surface. 403 * 404 * @param surface The surface to render 405 * 406 * @return True if the initialization was successful, false otherwise. 407 */ initialize(Surface surface)408 boolean initialize(Surface surface) throws OutOfResourcesException { 409 boolean status = !mInitialized; 410 mInitialized = true; 411 updateEnabledState(surface); 412 setSurface(surface); 413 return status; 414 } 415 416 /** 417 * Initializes the threaded renderer for the specified surface and setup the 418 * renderer for drawing, if needed. This is invoked when the ViewAncestor has 419 * potentially lost the threaded renderer. The threaded renderer should be 420 * reinitialized and setup when the render {@link #isRequested()} and 421 * {@link #isEnabled()}. 422 * 423 * @param width The width of the drawing surface. 424 * @param height The height of the drawing surface. 425 * @param attachInfo Information about the window. 426 * @param surface The surface to render 427 * @param surfaceInsets The drawing surface insets to apply 428 * 429 * @return true if the surface was initialized, false otherwise. Returning 430 * false might mean that the surface was already initialized. 431 */ initializeIfNeeded(int width, int height, View.AttachInfo attachInfo, Surface surface, Rect surfaceInsets)432 boolean initializeIfNeeded(int width, int height, View.AttachInfo attachInfo, 433 Surface surface, Rect surfaceInsets) throws OutOfResourcesException { 434 if (isRequested()) { 435 // We lost the gl context, so recreate it. 436 if (!isEnabled()) { 437 if (initialize(surface)) { 438 setup(width, height, attachInfo, surfaceInsets); 439 return true; 440 } 441 } 442 } 443 return false; 444 } 445 446 /** 447 * Updates the threaded renderer for the specified surface. 448 * 449 * @param surface The surface to render 450 */ updateSurface(Surface surface)451 void updateSurface(Surface surface) throws OutOfResourcesException { 452 updateEnabledState(surface); 453 setSurface(surface); 454 } 455 456 @Override setSurface(Surface surface)457 public void setSurface(Surface surface) { 458 // TODO: Do we ever pass a non-null but isValid() = false surface? 459 // This is here to be super conservative for ViewRootImpl 460 if (surface != null && surface.isValid()) { 461 super.setSurface(surface); 462 } else { 463 super.setSurface(null); 464 } 465 } 466 467 /** 468 * Registers a callback to be executed when the next frame is being drawn on RenderThread. This 469 * callback will be executed on a RenderThread worker thread, and only used for the next frame 470 * and thus it will only fire once. 471 * 472 * @param callback The callback to register. 473 */ registerRtFrameCallback(@onNull FrameDrawingCallback callback)474 void registerRtFrameCallback(@NonNull FrameDrawingCallback callback) { 475 if (mNextRtFrameCallbacks == null) { 476 mNextRtFrameCallbacks = new ArrayList<>(); 477 } 478 mNextRtFrameCallbacks.add(callback); 479 } 480 481 /** 482 * Remove a frame drawing callback that was added via 483 * {@link #registerRtFrameCallback(FrameDrawingCallback)} 484 * 485 * @param callback The callback to unregister. 486 */ unregisterRtFrameCallback(@onNull FrameDrawingCallback callback)487 void unregisterRtFrameCallback(@NonNull FrameDrawingCallback callback) { 488 if (mNextRtFrameCallbacks == null) { 489 return; 490 } 491 mNextRtFrameCallbacks.remove(callback); 492 } 493 494 /** 495 * Destroys all hardware rendering resources associated with the specified 496 * view hierarchy. 497 * 498 * @param view The root of the view hierarchy 499 */ destroyHardwareResources(View view)500 void destroyHardwareResources(View view) { 501 destroyResources(view); 502 clearContent(); 503 } 504 destroyResources(View view)505 private static void destroyResources(View view) { 506 view.destroyHardwareResources(); 507 } 508 509 /** 510 * Sets up the renderer for drawing. 511 * 512 * @param width The width of the drawing surface. 513 * @param height The height of the drawing surface. 514 * @param attachInfo Information about the window. 515 * @param surfaceInsets The drawing surface insets to apply 516 */ setup(int width, int height, AttachInfo attachInfo, Rect surfaceInsets)517 void setup(int width, int height, AttachInfo attachInfo, Rect surfaceInsets) { 518 mWidth = width; 519 mHeight = height; 520 521 if (surfaceInsets != null && (surfaceInsets.left != 0 || surfaceInsets.right != 0 522 || surfaceInsets.top != 0 || surfaceInsets.bottom != 0)) { 523 mInsetLeft = surfaceInsets.left; 524 mInsetTop = surfaceInsets.top; 525 mSurfaceWidth = width + mInsetLeft + surfaceInsets.right; 526 mSurfaceHeight = height + mInsetTop + surfaceInsets.bottom; 527 528 // If the surface has insets, it can't be opaque. 529 setOpaque(false); 530 } else { 531 mInsetLeft = 0; 532 mInsetTop = 0; 533 mSurfaceWidth = width; 534 mSurfaceHeight = height; 535 } 536 537 mRootNode.setLeftTopRightBottom(-mInsetLeft, -mInsetTop, mSurfaceWidth, mSurfaceHeight); 538 539 setLightCenter(attachInfo); 540 } 541 542 /** 543 * Whether or not the renderer owns the SurfaceControl's opacity. If true, use 544 * {@link #setSurfaceControlOpaque(boolean)} to update the opacity 545 */ rendererOwnsSurfaceControlOpacity()546 public boolean rendererOwnsSurfaceControlOpacity() { 547 return mWebViewOverlayProvider.mSurfaceControl != null; 548 } 549 550 /** 551 * Sets the SurfaceControl's opacity that this HardwareRenderer is rendering onto. The renderer 552 * may opt to override the opacity, and will return the value that is ultimately set 553 * 554 * @return true if the surface is opaque, false otherwise 555 * 556 * @hide 557 */ setSurfaceControlOpaque(boolean opaque)558 public boolean setSurfaceControlOpaque(boolean opaque) { 559 return mWebViewOverlayProvider.setSurfaceControlOpaque(opaque); 560 } 561 updateWebViewOverlayCallbacks()562 private void updateWebViewOverlayCallbacks() { 563 boolean shouldEnable = mWebViewOverlayProvider.shouldEnableOverlaySupport(); 564 if (shouldEnable != mWebViewOverlaysEnabled) { 565 mWebViewOverlaysEnabled = shouldEnable; 566 if (shouldEnable) { 567 setASurfaceTransactionCallback(mWebViewOverlayProvider); 568 setPrepareSurfaceControlForWebviewCallback(mWebViewOverlayProvider); 569 } else { 570 setASurfaceTransactionCallback(null); 571 setPrepareSurfaceControlForWebviewCallback(null); 572 } 573 } 574 } 575 576 @Override setSurfaceControl(@ullable SurfaceControl surfaceControl)577 public void setSurfaceControl(@Nullable SurfaceControl surfaceControl) { 578 super.setSurfaceControl(surfaceControl); 579 mWebViewOverlayProvider.setSurfaceControl(surfaceControl); 580 updateWebViewOverlayCallbacks(); 581 } 582 583 /** 584 * Sets the BLASTBufferQueue being used for rendering. This is required to be specified 585 * for WebView overlay support 586 */ setBlastBufferQueue(@ullable BLASTBufferQueue blastBufferQueue)587 public void setBlastBufferQueue(@Nullable BLASTBufferQueue blastBufferQueue) { 588 mWebViewOverlayProvider.setBLASTBufferQueue(blastBufferQueue); 589 updateWebViewOverlayCallbacks(); 590 } 591 592 /** 593 * Updates the light position based on the position of the window. 594 * 595 * @param attachInfo Information about the window. 596 */ setLightCenter(AttachInfo attachInfo)597 void setLightCenter(AttachInfo attachInfo) { 598 // Adjust light position for window offsets. 599 DisplayMetrics displayMetrics = new DisplayMetrics(); 600 attachInfo.mDisplay.getRealMetrics(displayMetrics); 601 final float lightX = displayMetrics.widthPixels / 2f - attachInfo.mWindowLeft; 602 final float lightY = mLightY - attachInfo.mWindowTop; 603 // To prevent shadow distortion on larger screens, scale the z position of the light source 604 // relative to the smallest screen dimension. 605 final float zRatio = Math.min(displayMetrics.widthPixels, displayMetrics.heightPixels) 606 / (450f * displayMetrics.density); 607 final float zWeightedAdjustment = (zRatio + 2) / 3f; 608 final float lightZ = mLightZ * zWeightedAdjustment; 609 610 setLightSourceGeometry(lightX, lightY, lightZ, mLightRadius); 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 */ getWidth()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 */ getHeight()629 int getHeight() { 630 return mHeight; 631 } 632 dumpArgsToFlags(String[] args)633 private static int dumpArgsToFlags(String[] args) { 634 // If there's no arguments, eg 'dumpsys gfxinfo', then dump everything. 635 // If there's a targetted package, eg 'dumpsys gfxinfo com.android.systemui', then only 636 // dump the summary information 637 if (args == null || args.length == 0) { 638 return FLAG_DUMP_ALL; 639 } 640 int flags = 0; 641 for (int i = 0; i < args.length; i++) { 642 switch (args[i]) { 643 case "framestats": 644 flags |= FLAG_DUMP_FRAMESTATS; 645 break; 646 case "reset": 647 flags |= FLAG_DUMP_RESET; 648 break; 649 case "-a": // magic option passed when dumping a bugreport. 650 flags = FLAG_DUMP_ALL; 651 break; 652 } 653 } 654 return flags; 655 } 656 657 /** @hide */ handleDumpGfxInfo(FileDescriptor fd, String[] args)658 public static void handleDumpGfxInfo(FileDescriptor fd, String[] args) { 659 dumpGlobalProfileInfo(fd, dumpArgsToFlags(args)); 660 WindowManagerGlobal.getInstance().dumpGfxInfo(fd, args); 661 } 662 663 /** 664 * Outputs extra debugging information in the specified file descriptor. 665 */ dumpGfxInfo(PrintWriter pw, FileDescriptor fd, String[] args)666 void dumpGfxInfo(PrintWriter pw, FileDescriptor fd, String[] args) { 667 pw.flush(); 668 dumpProfileInfo(fd, dumpArgsToFlags(args)); 669 } 670 captureRenderingCommands()671 Picture captureRenderingCommands() { 672 return null; 673 } 674 675 @Override loadSystemProperties()676 public boolean loadSystemProperties() { 677 boolean changed = super.loadSystemProperties(); 678 if (changed) { 679 invalidateRoot(); 680 } 681 return changed; 682 } 683 updateViewTreeDisplayList(View view)684 private void updateViewTreeDisplayList(View view) { 685 view.mPrivateFlags |= View.PFLAG_DRAWN; 686 view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED) 687 == View.PFLAG_INVALIDATED; 688 view.mPrivateFlags &= ~View.PFLAG_INVALIDATED; 689 view.updateDisplayListIfDirty(); 690 view.mRecreateDisplayList = false; 691 } 692 updateRootDisplayList(View view, DrawCallbacks callbacks)693 private void updateRootDisplayList(View view, DrawCallbacks callbacks) { 694 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Record View#draw()"); 695 updateViewTreeDisplayList(view); 696 697 // Consume and set the frame callback after we dispatch draw to the view above, but before 698 // onPostDraw below which may reset the callback for the next frame. This ensures that 699 // updates to the frame callback during scroll handling will also apply in this frame. 700 if (mNextRtFrameCallbacks != null) { 701 final ArrayList<FrameDrawingCallback> frameCallbacks = mNextRtFrameCallbacks; 702 mNextRtFrameCallbacks = null; 703 setFrameCallback(new FrameDrawingCallback() { 704 @Override 705 public void onFrameDraw(long frame) { 706 } 707 708 @Override 709 public FrameCommitCallback onFrameDraw(int syncResult, long frame) { 710 ArrayList<FrameCommitCallback> frameCommitCallbacks = new ArrayList<>(); 711 for (int i = 0; i < frameCallbacks.size(); ++i) { 712 FrameCommitCallback frameCommitCallback = frameCallbacks.get(i) 713 .onFrameDraw(syncResult, frame); 714 if (frameCommitCallback != null) { 715 frameCommitCallbacks.add(frameCommitCallback); 716 } 717 } 718 719 if (frameCommitCallbacks.isEmpty()) { 720 return null; 721 } 722 723 return didProduceBuffer -> { 724 for (int i = 0; i < frameCommitCallbacks.size(); ++i) { 725 frameCommitCallbacks.get(i).onFrameCommit(didProduceBuffer); 726 } 727 }; 728 } 729 }); 730 } 731 732 if (mRootNodeNeedsUpdate || !mRootNode.hasDisplayList()) { 733 RecordingCanvas canvas = mRootNode.beginRecording(mSurfaceWidth, mSurfaceHeight); 734 try { 735 final int saveCount = canvas.save(); 736 canvas.translate(mInsetLeft, mInsetTop); 737 callbacks.onPreDraw(canvas); 738 739 canvas.enableZ(); 740 canvas.drawRenderNode(view.updateDisplayListIfDirty()); 741 canvas.disableZ(); 742 743 callbacks.onPostDraw(canvas); 744 canvas.restoreToCount(saveCount); 745 mRootNodeNeedsUpdate = false; 746 } finally { 747 mRootNode.endRecording(); 748 } 749 } 750 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 751 } 752 753 /** 754 * Interface used to receive callbacks whenever a view is drawn by 755 * a threaded renderer instance. 756 */ 757 interface DrawCallbacks { 758 /** 759 * Invoked before a view is drawn by a threaded renderer. 760 * This method can be used to apply transformations to the 761 * canvas but no drawing command should be issued. 762 * 763 * @param canvas The Canvas used to render the view. 764 */ onPreDraw(RecordingCanvas canvas)765 void onPreDraw(RecordingCanvas canvas); 766 767 /** 768 * Invoked after a view is drawn by a threaded renderer. 769 * It is safe to invoke drawing commands from this method. 770 * 771 * @param canvas The Canvas used to render the view. 772 */ onPostDraw(RecordingCanvas canvas)773 void onPostDraw(RecordingCanvas canvas); 774 } 775 776 /** 777 * Indicates that the content drawn by DrawCallbacks needs to 778 * be updated, which will be done by the next call to draw() 779 */ invalidateRoot()780 void invalidateRoot() { 781 mRootNodeNeedsUpdate = true; 782 } 783 784 /** 785 * Draws the specified view. 786 * 787 * @param view The view to draw. 788 * @param attachInfo AttachInfo tied to the specified view. 789 */ draw(View view, AttachInfo attachInfo, DrawCallbacks callbacks)790 void draw(View view, AttachInfo attachInfo, DrawCallbacks callbacks) { 791 attachInfo.mViewRootImpl.mViewFrameInfo.markDrawStart(); 792 793 updateRootDisplayList(view, callbacks); 794 795 // register animating rendernodes which started animating prior to renderer 796 // creation, which is typical for animators started prior to first draw 797 if (attachInfo.mPendingAnimatingRenderNodes != null) { 798 final int count = attachInfo.mPendingAnimatingRenderNodes.size(); 799 for (int i = 0; i < count; i++) { 800 registerAnimatingRenderNode( 801 attachInfo.mPendingAnimatingRenderNodes.get(i)); 802 } 803 attachInfo.mPendingAnimatingRenderNodes.clear(); 804 // We don't need this anymore as subsequent calls to 805 // ViewRootImpl#attachRenderNodeAnimator will go directly to us. 806 attachInfo.mPendingAnimatingRenderNodes = null; 807 } 808 809 final FrameInfo frameInfo = attachInfo.mViewRootImpl.getUpdatedFrameInfo(); 810 811 int syncResult = syncAndDrawFrame(frameInfo); 812 if ((syncResult & SYNC_LOST_SURFACE_REWARD_IF_FOUND) != 0) { 813 Log.w("OpenGLRenderer", "Surface lost, forcing relayout"); 814 // We lost our surface. For a relayout next frame which should give us a new 815 // surface from WindowManager, which hopefully will work. 816 attachInfo.mViewRootImpl.mForceNextWindowRelayout = true; 817 attachInfo.mViewRootImpl.requestLayout(); 818 } 819 if ((syncResult & SYNC_REDRAW_REQUESTED) != 0) { 820 attachInfo.mViewRootImpl.invalidate(); 821 } 822 } 823 824 /** The root of everything */ getRootNode()825 public @NonNull RenderNode getRootNode() { 826 return mRootNode; 827 } 828 829 /** 830 * Basic synchronous renderer. Currently only used to render the Magnifier, so use with care. 831 * TODO: deduplicate against ThreadedRenderer. 832 * 833 * @hide 834 */ 835 public static class SimpleRenderer extends HardwareRenderer { 836 private final float mLightY, mLightZ, mLightRadius; 837 SimpleRenderer(final Context context, final String name, final Surface surface)838 public SimpleRenderer(final Context context, final String name, final Surface surface) { 839 super(); 840 setName(name); 841 setOpaque(false); 842 setSurface(surface); 843 final TypedArray a = context.obtainStyledAttributes(null, R.styleable.Lighting, 0, 0); 844 mLightY = a.getDimension(R.styleable.Lighting_lightY, 0); 845 mLightZ = a.getDimension(R.styleable.Lighting_lightZ, 0); 846 mLightRadius = a.getDimension(R.styleable.Lighting_lightRadius, 0); 847 final float ambientShadowAlpha = a.getFloat(R.styleable.Lighting_ambientShadowAlpha, 0); 848 final float spotShadowAlpha = a.getFloat(R.styleable.Lighting_spotShadowAlpha, 0); 849 a.recycle(); 850 setLightSourceAlpha(ambientShadowAlpha, spotShadowAlpha); 851 } 852 853 /** 854 * Set the light center. 855 */ setLightCenter(final Display display, final int windowLeft, final int windowTop)856 public void setLightCenter(final Display display, 857 final int windowLeft, final int windowTop) { 858 // Adjust light position for window offsets. 859 DisplayMetrics displayMetrics = new DisplayMetrics(); 860 display.getRealMetrics(displayMetrics); 861 final float lightX = displayMetrics.widthPixels / 2f - windowLeft; 862 final float lightY = mLightY - windowTop; 863 // To prevent shadow distortion on larger screens, scale the z position of the light 864 // source relative to the smallest screen dimension. 865 final float zRatio = Math.min(displayMetrics.widthPixels, displayMetrics.heightPixels) 866 / (450f * displayMetrics.density); 867 final float zWeightedAdjustment = (zRatio + 2) / 3f; 868 final float lightZ = mLightZ * zWeightedAdjustment; 869 870 setLightSourceGeometry(lightX, lightY, lightZ, mLightRadius); 871 } 872 getRootNode()873 public RenderNode getRootNode() { 874 return mRootNode; 875 } 876 877 /** 878 * Draw the surface. 879 */ draw(final FrameDrawingCallback callback)880 public void draw(final FrameDrawingCallback callback) { 881 final long vsync = AnimationUtils.currentAnimationTimeMillis() * 1000000L; 882 if (callback != null) { 883 setFrameCallback(callback); 884 } 885 createRenderRequest() 886 .setVsyncTime(vsync) 887 .syncAndDraw(); 888 } 889 } 890 } 891