• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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