blob: f18aa81b95e5017025339d7662fba1f67fc2aca5 [file] [log] [blame]
John Reckcec24ae2013-11-05 13:27:50 -08001/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.view;
18
Chris Craik2507c342015-05-04 14:36:49 -070019import android.annotation.NonNull;
Issei Suzuki9127d3c2019-06-27 12:29:30 +020020import android.annotation.Nullable;
John Reckb8802b12014-06-16 15:28:50 -070021import android.content.Context;
Alan Viverette58c42c32014-07-12 20:33:45 -070022import android.content.res.TypedArray;
John Reck8785ceb2018-10-29 16:45:58 -070023import android.graphics.HardwareRenderer;
John Reck5cca8f22018-12-10 17:06:22 -080024import android.graphics.Picture;
Alan Viverette50210d92015-05-14 18:05:36 -070025import android.graphics.Point;
John Reck32f140aa62018-10-04 15:08:24 -070026import android.graphics.RecordingCanvas;
Alan Viveretteccb11e12014-07-08 16:04:02 -070027import android.graphics.Rect;
John Reck32f140aa62018-10-04 15:08:24 -070028import android.graphics.RenderNode;
Jaesung Chung9a89d832017-05-16 01:54:17 +090029import android.os.SystemProperties;
John Reckcec24ae2013-11-05 13:27:50 -080030import android.os.Trace;
John Reckcec24ae2013-11-05 13:27:50 -080031import android.view.Surface.OutOfResourcesException;
32import android.view.View.AttachInfo;
Mihai Popa4bcd4d402018-02-07 17:13:51 +000033import android.view.animation.AnimationUtils;
John Reckcec24ae2013-11-05 13:27:50 -080034
John Reckba6adf62015-02-19 14:36:50 -080035import com.android.internal.R;
36
John Reckfe5e7b72014-05-23 17:42:28 -070037import java.io.FileDescriptor;
John Reckcec24ae2013-11-05 13:27:50 -080038import java.io.PrintWriter;
Issei Suzuki9127d3c2019-06-27 12:29:30 +020039import java.util.ArrayList;
John Reckcec24ae2013-11-05 13:27:50 -080040
41/**
Stan Iliev45faba52016-06-28 13:33:15 -040042 * Threaded renderer that proxies the rendering to a render thread. Most calls
John Reck4f02bf42014-01-03 18:09:17 -080043 * are currently synchronous.
John Reckcec24ae2013-11-05 13:27:50 -080044 *
45 * The UI thread can block on the RenderThread, but RenderThread must never
46 * block on the UI thread.
47 *
John Reck4f02bf42014-01-03 18:09:17 -080048 * ThreadedRenderer creates an instance of RenderProxy. RenderProxy in turn creates
49 * and manages a CanvasContext on the RenderThread. The CanvasContext is fully managed
50 * by the lifecycle of the RenderProxy.
51 *
John Reckcec24ae2013-11-05 13:27:50 -080052 * Note that although currently the EGL context & surfaces are created & managed
53 * by the render thread, the goal is to move that into a shared structure that can
54 * be managed by both threads. EGLSurface creation & deletion should ideally be
55 * done on the UI thread and not the RenderThread to avoid stalling the
56 * RenderThread with surface buffer allocation.
57 *
58 * @hide
59 */
John Reck8785ceb2018-10-29 16:45:58 -070060public final class ThreadedRenderer extends HardwareRenderer {
John Reck51aaf902015-12-02 15:08:07 -080061 /**
Stan Iliev45faba52016-06-28 13:33:15 -040062 * System property used to enable or disable threaded rendering profiling.
John Reck51aaf902015-12-02 15:08:07 -080063 * The default value of this property is assumed to be false.
64 *
65 * When profiling is enabled, the adb shell dumpsys gfxinfo command will
66 * output extra information about the time taken to execute by the last
67 * frames.
68 *
69 * Possible values:
70 * "true", to enable profiling
71 * "visual_bars", to enable profiling and visualize the results on screen
72 * "false", to disable profiling
73 *
74 * @see #PROFILE_PROPERTY_VISUALIZE_BARS
75 *
76 * @hide
77 */
78 public static final String PROFILE_PROPERTY = "debug.hwui.profile";
79
80 /**
81 * Value for {@link #PROFILE_PROPERTY}. When the property is set to this
82 * value, profiling data will be visualized on screen as a bar chart.
83 *
84 * @hide
85 */
86 public static final String PROFILE_PROPERTY_VISUALIZE_BARS = "visual_bars";
87
88 /**
89 * System property used to specify the number of frames to be used
Stan Iliev45faba52016-06-28 13:33:15 -040090 * when doing threaded rendering profiling.
John Reck51aaf902015-12-02 15:08:07 -080091 * The default value of this property is #PROFILE_MAX_FRAMES.
92 *
93 * When profiling is enabled, the adb shell dumpsys gfxinfo command will
94 * output extra information about the time taken to execute by the last
95 * frames.
96 *
97 * Possible values:
98 * "60", to set the limit of frames to 60
99 */
100 static final String PROFILE_MAXFRAMES_PROPERTY = "debug.hwui.profile.maxframes";
101
102 /**
103 * System property used to debug EGL configuration choice.
104 *
105 * Possible values:
106 * "choice", print the chosen configuration only
107 * "all", print all possible configurations
108 */
109 static final String PRINT_CONFIG_PROPERTY = "debug.hwui.print_config";
110
111 /**
112 * Turn on to draw dirty regions every other frame.
113 *
114 * Possible values:
115 * "true", to enable dirty regions debugging
116 * "false", to disable dirty regions debugging
117 *
118 * @hide
119 */
120 public static final String DEBUG_DIRTY_REGIONS_PROPERTY = "debug.hwui.show_dirty_regions";
121
122 /**
123 * Turn on to flash hardware layers when they update.
124 *
125 * Possible values:
126 * "true", to enable hardware layers updates debugging
127 * "false", to disable hardware layers updates debugging
128 *
129 * @hide
130 */
131 public static final String DEBUG_SHOW_LAYERS_UPDATES_PROPERTY =
132 "debug.hwui.show_layers_updates";
133
134 /**
135 * Controls overdraw debugging.
136 *
137 * Possible values:
138 * "false", to disable overdraw debugging
139 * "show", to show overdraw areas on screen
140 * "count", to display an overdraw counter
141 *
142 * @hide
143 */
144 public static final String DEBUG_OVERDRAW_PROPERTY = "debug.hwui.overdraw";
145
146 /**
147 * Value for {@link #DEBUG_OVERDRAW_PROPERTY}. When the property is set to this
148 * value, overdraw will be shown on screen by coloring pixels.
149 *
150 * @hide
151 */
152 public static final String OVERDRAW_PROPERTY_SHOW = "show";
153
154 /**
155 * Turn on to debug non-rectangular clip operations.
156 *
157 * Possible values:
158 * "hide", to disable this debug mode
159 * "highlight", highlight drawing commands tested against a non-rectangular clip
160 * "stencil", renders the clip region on screen when set
161 *
162 * @hide
163 */
164 public static final String DEBUG_SHOW_NON_RECTANGULAR_CLIP_PROPERTY =
165 "debug.hwui.show_non_rect_clip";
166
John Reck9f516442017-09-25 10:27:21 -0700167 /**
168 * Sets the FPS devisor to lower the FPS.
169 *
170 * Sets a positive integer as a divisor. 1 (the default value) menas the full FPS, and 2
171 * means half the full FPS.
172 *
173 *
174 * @hide
175 */
176 public static final String DEBUG_FPS_DIVISOR = "debug.hwui.fps_divisor";
177
John Reckde20c572018-10-26 15:47:55 -0700178 /**
179 * Forces smart-dark to be always on.
180 * @hide
181 */
John Reck0b5db0e2019-05-02 12:59:40 -0700182 public static final String DEBUG_FORCE_DARK = "debug.hwui.force_dark";
John Reckde20c572018-10-26 15:47:55 -0700183
Jorim Jaggi767e25e2018-04-04 23:07:35 +0200184 public static int EGL_CONTEXT_PRIORITY_HIGH_IMG = 0x3101;
185 public static int EGL_CONTEXT_PRIORITY_MEDIUM_IMG = 0x3102;
186 public static int EGL_CONTEXT_PRIORITY_LOW_IMG = 0x3103;
187
Jaesung Chung9a89d832017-05-16 01:54:17 +0900188 static {
189 // Try to check OpenGL support early if possible.
190 isAvailable();
191 }
192
John Reck51aaf902015-12-02 15:08:07 -0800193 /**
Stan Iliev45faba52016-06-28 13:33:15 -0400194 * A process can set this flag to false to prevent the use of threaded
John Reck51aaf902015-12-02 15:08:07 -0800195 * rendering.
196 *
197 * @hide
198 */
199 public static boolean sRendererDisabled = false;
200
201 /**
Stan Iliev45faba52016-06-28 13:33:15 -0400202 * Further threaded renderer disabling for the system process.
John Reck51aaf902015-12-02 15:08:07 -0800203 *
204 * @hide
205 */
206 public static boolean sSystemRendererDisabled = false;
207
208 /**
Stan Iliev45faba52016-06-28 13:33:15 -0400209 * Invoke this method to disable threaded rendering in the current process.
John Reck51aaf902015-12-02 15:08:07 -0800210 *
211 * @hide
212 */
213 public static void disable(boolean system) {
214 sRendererDisabled = true;
215 if (system) {
216 sSystemRendererDisabled = true;
217 }
218 }
219
220 public static boolean sTrimForeground = false;
221
222 /**
Stan Iliev45faba52016-06-28 13:33:15 -0400223 * Controls whether or not the renderer should aggressively trim
224 * memory. Note that this must not be set for any process that uses
225 * WebView! This should be only used by system_process or similar
John Reck51aaf902015-12-02 15:08:07 -0800226 * that do not go into the background.
227 */
228 public static void enableForegroundTrimming() {
229 sTrimForeground = true;
230 }
231
Jaesung Chung9a89d832017-05-16 01:54:17 +0900232 private static Boolean sSupportsOpenGL;
Derek Sollenbergerf64c34e2016-06-28 16:39:13 -0400233
John Reck51aaf902015-12-02 15:08:07 -0800234 /**
Stan Iliev45faba52016-06-28 13:33:15 -0400235 * Indicates whether threaded rendering is available under any form for
John Reck51aaf902015-12-02 15:08:07 -0800236 * the view hierarchy.
237 *
Stan Iliev45faba52016-06-28 13:33:15 -0400238 * @return True if the view hierarchy can potentially be defer rendered,
John Reck51aaf902015-12-02 15:08:07 -0800239 * false otherwise
240 */
241 public static boolean isAvailable() {
Jaesung Chung9a89d832017-05-16 01:54:17 +0900242 if (sSupportsOpenGL != null) {
243 return sSupportsOpenGL.booleanValue();
244 }
245 if (SystemProperties.getInt("ro.kernel.qemu", 0) == 0) {
246 // Device is not an emulator.
247 sSupportsOpenGL = true;
248 return true;
249 }
250 int qemu_gles = SystemProperties.getInt("qemu.gles", -1);
251 if (qemu_gles == -1) {
252 // In this case, the value of the qemu.gles property is not ready
253 // because the SurfaceFlinger service may not start at this point.
254 return false;
255 }
256 // In the emulator this property will be set > 0 when OpenGL ES 2.0 is
257 // enabled, 0 otherwise. On old emulator versions it will be undefined.
258 sSupportsOpenGL = qemu_gles > 0;
259 return sSupportsOpenGL.booleanValue();
John Reck51aaf902015-12-02 15:08:07 -0800260 }
261
262 /**
Stan Iliev45faba52016-06-28 13:33:15 -0400263 * Creates a threaded renderer using OpenGL.
John Reck51aaf902015-12-02 15:08:07 -0800264 *
265 * @param translucent True if the surface is translucent, false otherwise
266 *
Stan Iliev45faba52016-06-28 13:33:15 -0400267 * @return A threaded renderer backed by OpenGL.
John Reck51aaf902015-12-02 15:08:07 -0800268 */
John Reckdf1742e2017-01-19 15:56:21 -0800269 public static ThreadedRenderer create(Context context, boolean translucent, String name) {
John Reck51aaf902015-12-02 15:08:07 -0800270 ThreadedRenderer renderer = null;
Derek Sollenbergerf64c34e2016-06-28 16:39:13 -0400271 if (isAvailable()) {
John Reckdf1742e2017-01-19 15:56:21 -0800272 renderer = new ThreadedRenderer(context, translucent, name);
John Reck51aaf902015-12-02 15:08:07 -0800273 }
274 return renderer;
275 }
276
John Reckfe5e7b72014-05-23 17:42:28 -0700277 private static final String[] VISUALIZERS = {
278 PROFILE_PROPERTY_VISUALIZE_BARS,
279 };
280
Alan Viveretteccb11e12014-07-08 16:04:02 -0700281 // Size of the rendered content.
John Reckcec24ae2013-11-05 13:27:50 -0800282 private int mWidth, mHeight;
Alan Viveretteccb11e12014-07-08 16:04:02 -0700283
284 // Actual size of the drawing surface.
285 private int mSurfaceWidth, mSurfaceHeight;
286
287 // Insets between the drawing surface and rendered content. These are
288 // applied as translation when updating the root render node.
289 private int mInsetTop, mInsetLeft;
290
Alan Viverette57774a82014-07-15 15:49:55 -0700291 // Whether the surface has insets. Used to protect opacity.
292 private boolean mHasInsets;
293
John Reck8785ceb2018-10-29 16:45:58 -0700294 // Light properties specified by the theme.
Alan Viverette58c42c32014-07-12 20:33:45 -0700295 private final float mLightY;
296 private final float mLightZ;
297 private final float mLightRadius;
Alan Viverette58c42c32014-07-12 20:33:45 -0700298
John Reckf7d9c1d2014-04-09 10:01:03 -0700299 private boolean mInitialized = false;
John Reck0a973302014-07-16 13:29:45 -0700300 private boolean mRootNodeNeedsUpdate;
John Reckcec24ae2013-11-05 13:27:50 -0800301
John Reck51aaf902015-12-02 15:08:07 -0800302 private boolean mEnabled;
303 private boolean mRequested = true;
304
Issei Suzuki9127d3c2019-06-27 12:29:30 +0200305 @Nullable
306 private ArrayList<FrameDrawingCallback> mNextRtFrameCallbacks;
Winson Chungf2131112018-12-10 16:11:28 -0800307
John Reckdf1742e2017-01-19 15:56:21 -0800308 ThreadedRenderer(Context context, boolean translucent, String name) {
John Reck8785ceb2018-10-29 16:45:58 -0700309 super();
310 setName(name);
311 setOpaque(!translucent);
312
Alan Viveretteed6f14a2014-08-26 14:53:28 -0700313 final TypedArray a = context.obtainStyledAttributes(null, R.styleable.Lighting, 0, 0);
Alan Viverette58c42c32014-07-12 20:33:45 -0700314 mLightY = a.getDimension(R.styleable.Lighting_lightY, 0);
315 mLightZ = a.getDimension(R.styleable.Lighting_lightZ, 0);
316 mLightRadius = a.getDimension(R.styleable.Lighting_lightRadius, 0);
John Reck8785ceb2018-10-29 16:45:58 -0700317 float ambientShadowAlpha = a.getFloat(R.styleable.Lighting_ambientShadowAlpha, 0);
318 float spotShadowAlpha = a.getFloat(R.styleable.Lighting_spotShadowAlpha, 0);
Alan Viverette58c42c32014-07-12 20:33:45 -0700319 a.recycle();
John Reck8785ceb2018-10-29 16:45:58 -0700320 setLightSourceAlpha(ambientShadowAlpha, spotShadowAlpha);
John Reckcec24ae2013-11-05 13:27:50 -0800321 }
322
John Reck8785ceb2018-10-29 16:45:58 -0700323 @Override
324 public void destroy() {
John Reckf7d9c1d2014-04-09 10:01:03 -0700325 mInitialized = false;
326 updateEnabledState(null);
John Reck8785ceb2018-10-29 16:45:58 -0700327 super.destroy();
John Reckcec24ae2013-11-05 13:27:50 -0800328 }
329
John Reck51aaf902015-12-02 15:08:07 -0800330 /**
Stan Iliev45faba52016-06-28 13:33:15 -0400331 * Indicates whether threaded rendering is currently enabled.
John Reck51aaf902015-12-02 15:08:07 -0800332 *
Stan Iliev45faba52016-06-28 13:33:15 -0400333 * @return True if threaded rendering is in use, false otherwise.
John Reck51aaf902015-12-02 15:08:07 -0800334 */
335 boolean isEnabled() {
336 return mEnabled;
337 }
338
339 /**
Stan Iliev45faba52016-06-28 13:33:15 -0400340 * Indicates whether threaded rendering is currently enabled.
John Reck51aaf902015-12-02 15:08:07 -0800341 *
Stan Iliev45faba52016-06-28 13:33:15 -0400342 * @param enabled True if the threaded renderer is in use, false otherwise.
John Reck51aaf902015-12-02 15:08:07 -0800343 */
344 void setEnabled(boolean enabled) {
345 mEnabled = enabled;
346 }
347
348 /**
Stan Iliev45faba52016-06-28 13:33:15 -0400349 * Indicates whether threaded rendering is currently request but not
John Reck51aaf902015-12-02 15:08:07 -0800350 * necessarily enabled yet.
351 *
352 * @return True if requested, false otherwise.
353 */
354 boolean isRequested() {
355 return mRequested;
356 }
357
358 /**
Stan Iliev45faba52016-06-28 13:33:15 -0400359 * Indicates whether threaded rendering is currently requested but not
John Reck51aaf902015-12-02 15:08:07 -0800360 * necessarily enabled yet.
John Reck51aaf902015-12-02 15:08:07 -0800361 */
362 void setRequested(boolean requested) {
363 mRequested = requested;
364 }
365
John Reckf7d9c1d2014-04-09 10:01:03 -0700366 private void updateEnabledState(Surface surface) {
367 if (surface == null || !surface.isValid()) {
368 setEnabled(false);
369 } else {
370 setEnabled(mInitialized);
371 }
372 }
373
John Reck51aaf902015-12-02 15:08:07 -0800374 /**
Stan Iliev45faba52016-06-28 13:33:15 -0400375 * Initializes the threaded renderer for the specified surface.
John Reck51aaf902015-12-02 15:08:07 -0800376 *
Stan Iliev45faba52016-06-28 13:33:15 -0400377 * @param surface The surface to render
John Reck51aaf902015-12-02 15:08:07 -0800378 *
379 * @return True if the initialization was successful, false otherwise.
380 */
John Reckcec24ae2013-11-05 13:27:50 -0800381 boolean initialize(Surface surface) throws OutOfResourcesException {
Thomas Buhot0bcd0cb2015-12-04 12:18:03 +0100382 boolean status = !mInitialized;
John Reckf7d9c1d2014-04-09 10:01:03 -0700383 mInitialized = true;
384 updateEnabledState(surface);
John Reck8785ceb2018-10-29 16:45:58 -0700385 setSurface(surface);
Dan Stoza5795d642014-06-20 13:01:36 -0700386 return status;
John Reckcec24ae2013-11-05 13:27:50 -0800387 }
388
John Reck51aaf902015-12-02 15:08:07 -0800389 /**
Stan Iliev45faba52016-06-28 13:33:15 -0400390 * Initializes the threaded renderer for the specified surface and setup the
John Reck51aaf902015-12-02 15:08:07 -0800391 * renderer for drawing, if needed. This is invoked when the ViewAncestor has
Stan Iliev45faba52016-06-28 13:33:15 -0400392 * potentially lost the threaded renderer. The threaded renderer should be
John Reck51aaf902015-12-02 15:08:07 -0800393 * reinitialized and setup when the render {@link #isRequested()} and
394 * {@link #isEnabled()}.
395 *
396 * @param width The width of the drawing surface.
397 * @param height The height of the drawing surface.
398 * @param attachInfo Information about the window.
Stan Iliev45faba52016-06-28 13:33:15 -0400399 * @param surface The surface to render
John Reck51aaf902015-12-02 15:08:07 -0800400 * @param surfaceInsets The drawing surface insets to apply
401 *
402 * @return true if the surface was initialized, false otherwise. Returning
403 * false might mean that the surface was already initialized.
404 */
405 boolean initializeIfNeeded(int width, int height, View.AttachInfo attachInfo,
406 Surface surface, Rect surfaceInsets) throws OutOfResourcesException {
407 if (isRequested()) {
408 // We lost the gl context, so recreate it.
409 if (!isEnabled()) {
410 if (initialize(surface)) {
411 setup(width, height, attachInfo, surfaceInsets);
412 return true;
413 }
414 }
415 }
416 return false;
417 }
418
419 /**
Stan Iliev45faba52016-06-28 13:33:15 -0400420 * Updates the threaded renderer for the specified surface.
John Reck51aaf902015-12-02 15:08:07 -0800421 *
Stan Iliev45faba52016-06-28 13:33:15 -0400422 * @param surface The surface to render
John Reck51aaf902015-12-02 15:08:07 -0800423 */
John Reckcec24ae2013-11-05 13:27:50 -0800424 void updateSurface(Surface surface) throws OutOfResourcesException {
John Reckf7d9c1d2014-04-09 10:01:03 -0700425 updateEnabledState(surface);
John Reck8785ceb2018-10-29 16:45:58 -0700426 setSurface(surface);
John Reckcec24ae2013-11-05 13:27:50 -0800427 }
428
John Reck8785ceb2018-10-29 16:45:58 -0700429 @Override
430 public void setSurface(Surface surface) {
431 // TODO: Do we ever pass a non-null but isValid() = false surface?
432 // This is here to be super conservative for ViewRootImpl
433 if (surface != null && surface.isValid()) {
434 super.setSurface(surface);
435 } else {
436 super.setSurface(null);
437 }
John Reck8afcc762016-04-13 10:24:06 -0700438 }
439
440 /**
Winson Chungf2131112018-12-10 16:11:28 -0800441 * Registers a callback to be executed when the next frame is being drawn on RenderThread. This
442 * callback will be executed on a RenderThread worker thread, and only used for the next frame
443 * and thus it will only fire once.
444 *
445 * @param callback The callback to register.
446 */
Issei Suzuki9127d3c2019-06-27 12:29:30 +0200447 void registerRtFrameCallback(@NonNull FrameDrawingCallback callback) {
448 if (mNextRtFrameCallbacks == null) {
449 mNextRtFrameCallbacks = new ArrayList<>();
450 }
451 mNextRtFrameCallbacks.add(callback);
Winson Chungf2131112018-12-10 16:11:28 -0800452 }
453
454 /**
John Reck51aaf902015-12-02 15:08:07 -0800455 * Destroys all hardware rendering resources associated with the specified
456 * view hierarchy.
457 *
458 * @param view The root of the view hierarchy
459 */
John Reckcec24ae2013-11-05 13:27:50 -0800460 void destroyHardwareResources(View view) {
John Reck4f02bf42014-01-03 18:09:17 -0800461 destroyResources(view);
John Reckfe5dfca2019-01-17 17:01:32 -0800462 clearContent();
John Reck4f02bf42014-01-03 18:09:17 -0800463 }
464
465 private static void destroyResources(View view) {
466 view.destroyHardwareResources();
John Reckcec24ae2013-11-05 13:27:50 -0800467 }
468
John Reck51aaf902015-12-02 15:08:07 -0800469 /**
John Reck51aaf902015-12-02 15:08:07 -0800470 * Sets up the renderer for drawing.
471 *
472 * @param width The width of the drawing surface.
473 * @param height The height of the drawing surface.
474 * @param attachInfo Information about the window.
475 * @param surfaceInsets The drawing surface insets to apply
476 */
Alan Viverette50210d92015-05-14 18:05:36 -0700477 void setup(int width, int height, AttachInfo attachInfo, Rect surfaceInsets) {
John Reckcec24ae2013-11-05 13:27:50 -0800478 mWidth = width;
479 mHeight = height;
Alan Viverette50210d92015-05-14 18:05:36 -0700480
Alan Viverette3aa1ffb2014-10-30 12:22:08 -0700481 if (surfaceInsets != null && (surfaceInsets.left != 0 || surfaceInsets.right != 0
482 || surfaceInsets.top != 0 || surfaceInsets.bottom != 0)) {
Alan Viverette57774a82014-07-15 15:49:55 -0700483 mHasInsets = true;
Alan Viveretteccb11e12014-07-08 16:04:02 -0700484 mInsetLeft = surfaceInsets.left;
485 mInsetTop = surfaceInsets.top;
486 mSurfaceWidth = width + mInsetLeft + surfaceInsets.right;
487 mSurfaceHeight = height + mInsetTop + surfaceInsets.bottom;
Alan Viverette57774a82014-07-15 15:49:55 -0700488
489 // If the surface has insets, it can't be opaque.
490 setOpaque(false);
Alan Viveretteccb11e12014-07-08 16:04:02 -0700491 } else {
Alan Viverette57774a82014-07-15 15:49:55 -0700492 mHasInsets = false;
Alan Viveretteccb11e12014-07-08 16:04:02 -0700493 mInsetLeft = 0;
494 mInsetTop = 0;
495 mSurfaceWidth = width;
496 mSurfaceHeight = height;
497 }
Alan Viverette50210d92015-05-14 18:05:36 -0700498
Alan Viveretteccb11e12014-07-08 16:04:02 -0700499 mRootNode.setLeftTopRightBottom(-mInsetLeft, -mInsetTop, mSurfaceWidth, mSurfaceHeight);
Alan Viverette50210d92015-05-14 18:05:36 -0700500
501 setLightCenter(attachInfo);
502 }
503
John Reck51aaf902015-12-02 15:08:07 -0800504 /**
505 * Updates the light position based on the position of the window.
506 *
507 * @param attachInfo Information about the window.
508 */
Alan Viverette50210d92015-05-14 18:05:36 -0700509 void setLightCenter(AttachInfo attachInfo) {
510 // Adjust light position for window offsets.
511 final Point displaySize = attachInfo.mPoint;
512 attachInfo.mDisplay.getRealSize(displaySize);
513 final float lightX = displaySize.x / 2f - attachInfo.mWindowLeft;
514 final float lightY = mLightY - attachInfo.mWindowTop;
John Reck8785ceb2018-10-29 16:45:58 -0700515 setLightSourceGeometry(lightX, lightY, mLightZ, mLightRadius);
Romain Guy26a2b972017-04-17 09:39:51 -0700516 }
517
518 /**
John Reck51aaf902015-12-02 15:08:07 -0800519 * Gets the current width of the surface. This is the width that the surface
520 * was last set to in a call to {@link #setup(int, int, View.AttachInfo, Rect)}.
521 *
522 * @return the current width of the surface
523 */
John Reckcec24ae2013-11-05 13:27:50 -0800524 int getWidth() {
525 return mWidth;
526 }
527
John Reck51aaf902015-12-02 15:08:07 -0800528 /**
529 * Gets the current height of the surface. This is the height that the surface
530 * was last set to in a call to {@link #setup(int, int, View.AttachInfo, Rect)}.
531 *
532 * @return the current width of the surface
533 */
John Reckcec24ae2013-11-05 13:27:50 -0800534 int getHeight() {
535 return mHeight;
536 }
537
John Reck51aaf902015-12-02 15:08:07 -0800538 /**
539 * Outputs extra debugging information in the specified file descriptor.
540 */
John Reckba6adf62015-02-19 14:36:50 -0800541 void dumpGfxInfo(PrintWriter pw, FileDescriptor fd, String[] args) {
John Reckfe5e7b72014-05-23 17:42:28 -0700542 pw.flush();
John Reck184264d2018-02-12 16:21:21 -0800543 // If there's no arguments, eg 'dumpsys gfxinfo', then dump everything.
544 // If there's a targetted package, eg 'dumpsys gfxinfo com.android.systemui', then only
545 // dump the summary information
546 int flags = (args == null || args.length == 0) ? FLAG_DUMP_ALL : 0;
John Reckba6adf62015-02-19 14:36:50 -0800547 for (int i = 0; i < args.length; i++) {
548 switch (args[i]) {
549 case "framestats":
550 flags |= FLAG_DUMP_FRAMESTATS;
551 break;
552 case "reset":
553 flags |= FLAG_DUMP_RESET;
554 break;
John Reck184264d2018-02-12 16:21:21 -0800555 case "-a": // magic option passed when dumping a bugreport.
556 flags = FLAG_DUMP_ALL;
557 break;
John Reckba6adf62015-02-19 14:36:50 -0800558 }
John Reckfe5e7b72014-05-23 17:42:28 -0700559 }
John Reck8785ceb2018-10-29 16:45:58 -0700560 dumpProfileInfo(fd, flags);
John Reckcec24ae2013-11-05 13:27:50 -0800561 }
562
John Reck5cca8f22018-12-10 17:06:22 -0800563 Picture captureRenderingCommands() {
564 return null;
565 }
566
John Reck8785ceb2018-10-29 16:45:58 -0700567 @Override
568 public boolean loadSystemProperties() {
569 boolean changed = super.loadSystemProperties();
John Reck23d307c2014-10-27 12:38:48 -0700570 if (changed) {
571 invalidateRoot();
572 }
John Reckfe5e7b72014-05-23 17:42:28 -0700573 return changed;
John Reckcec24ae2013-11-05 13:27:50 -0800574 }
575
John Reck0a973302014-07-16 13:29:45 -0700576 private void updateViewTreeDisplayList(View view) {
John Reckcec24ae2013-11-05 13:27:50 -0800577 view.mPrivateFlags |= View.PFLAG_DRAWN;
John Reckcec24ae2013-11-05 13:27:50 -0800578 view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
579 == View.PFLAG_INVALIDATED;
580 view.mPrivateFlags &= ~View.PFLAG_INVALIDATED;
Chris Craik31a2d062015-05-01 14:22:47 -0700581 view.updateDisplayListIfDirty();
John Reckcec24ae2013-11-05 13:27:50 -0800582 view.mRecreateDisplayList = false;
John Reckbc0cc022014-04-11 16:08:14 -0700583 }
584
Stan Iliev45faba52016-06-28 13:33:15 -0400585 private void updateRootDisplayList(View view, DrawCallbacks callbacks) {
Chris Craik70850ea2014-11-18 10:49:23 -0800586 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Record View#draw()");
John Reck0a973302014-07-16 13:29:45 -0700587 updateViewTreeDisplayList(view);
588
Winson Chungf2131112018-12-10 16:11:28 -0800589 // Consume and set the frame callback after we dispatch draw to the view above, but before
590 // onPostDraw below which may reset the callback for the next frame. This ensures that
591 // updates to the frame callback during scroll handling will also apply in this frame.
Issei Suzuki9127d3c2019-06-27 12:29:30 +0200592 if (mNextRtFrameCallbacks != null) {
593 final ArrayList<FrameDrawingCallback> frameCallbacks = mNextRtFrameCallbacks;
594 mNextRtFrameCallbacks = null;
595 setFrameCallback(frame -> {
596 for (int i = 0; i < frameCallbacks.size(); ++i) {
597 frameCallbacks.get(i).onFrameDraw(frame);
598 }
599 });
Winson Chungf2131112018-12-10 16:11:28 -0800600 }
601
John Reckc7ddcf32018-10-25 13:56:17 -0700602 if (mRootNodeNeedsUpdate || !mRootNode.hasDisplayList()) {
John Recke57475e2019-02-20 17:39:52 -0800603 RecordingCanvas canvas = mRootNode.beginRecording(mSurfaceWidth, mSurfaceHeight);
John Reck0a973302014-07-16 13:29:45 -0700604 try {
Alan Viverettedbed8932014-08-06 17:54:52 -0700605 final int saveCount = canvas.save();
John Reck0a973302014-07-16 13:29:45 -0700606 canvas.translate(mInsetLeft, mInsetTop);
Stan Iliev45faba52016-06-28 13:33:15 -0400607 callbacks.onPreDraw(canvas);
Chris Craikabedca32014-08-28 15:03:55 -0700608
John Reck8785ceb2018-10-29 16:45:58 -0700609 canvas.enableZ();
Chris Craik31a2d062015-05-01 14:22:47 -0700610 canvas.drawRenderNode(view.updateDisplayListIfDirty());
John Reck8785ceb2018-10-29 16:45:58 -0700611 canvas.disableZ();
Chris Craikabedca32014-08-28 15:03:55 -0700612
Stan Iliev45faba52016-06-28 13:33:15 -0400613 callbacks.onPostDraw(canvas);
Alan Viverettedbed8932014-08-06 17:54:52 -0700614 canvas.restoreToCount(saveCount);
John Reck0a973302014-07-16 13:29:45 -0700615 mRootNodeNeedsUpdate = false;
616 } finally {
John Reck8785ceb2018-10-29 16:45:58 -0700617 mRootNode.endRecording();
John Reck0a973302014-07-16 13:29:45 -0700618 }
619 }
620 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
621 }
622
Skuhneea7a7fb2015-08-28 07:10:31 -0700623 /**
John Reck51aaf902015-12-02 15:08:07 -0800624 * Interface used to receive callbacks whenever a view is drawn by
Stan Iliev45faba52016-06-28 13:33:15 -0400625 * a threaded renderer instance.
John Reck51aaf902015-12-02 15:08:07 -0800626 */
Stan Iliev45faba52016-06-28 13:33:15 -0400627 interface DrawCallbacks {
John Reck51aaf902015-12-02 15:08:07 -0800628 /**
Stan Iliev45faba52016-06-28 13:33:15 -0400629 * Invoked before a view is drawn by a threaded renderer.
John Reck51aaf902015-12-02 15:08:07 -0800630 * This method can be used to apply transformations to the
631 * canvas but no drawing command should be issued.
632 *
633 * @param canvas The Canvas used to render the view.
634 */
John Reck32f140aa62018-10-04 15:08:24 -0700635 void onPreDraw(RecordingCanvas canvas);
John Reck51aaf902015-12-02 15:08:07 -0800636
637 /**
Stan Iliev45faba52016-06-28 13:33:15 -0400638 * Invoked after a view is drawn by a threaded renderer.
John Reck51aaf902015-12-02 15:08:07 -0800639 * It is safe to invoke drawing commands from this method.
640 *
641 * @param canvas The Canvas used to render the view.
642 */
John Reck32f140aa62018-10-04 15:08:24 -0700643 void onPostDraw(RecordingCanvas canvas);
John Reck51aaf902015-12-02 15:08:07 -0800644 }
645
646 /**
Stan Iliev45faba52016-06-28 13:33:15 -0400647 * Indicates that the content drawn by DrawCallbacks needs to
John Reck51aaf902015-12-02 15:08:07 -0800648 * be updated, which will be done by the next call to draw()
649 */
John Reck0a973302014-07-16 13:29:45 -0700650 void invalidateRoot() {
651 mRootNodeNeedsUpdate = true;
652 }
653
John Reck51aaf902015-12-02 15:08:07 -0800654 /**
655 * Draws the specified view.
656 *
657 * @param view The view to draw.
658 * @param attachInfo AttachInfo tied to the specified view.
John Reck51aaf902015-12-02 15:08:07 -0800659 */
Winson Chungf2131112018-12-10 16:11:28 -0800660 void draw(View view, AttachInfo attachInfo, DrawCallbacks callbacks) {
John Reckba6adf62015-02-19 14:36:50 -0800661 final Choreographer choreographer = attachInfo.mViewRootImpl.mChoreographer;
662 choreographer.mFrameInfo.markDrawStart();
John Reckfe5e7b72014-05-23 17:42:28 -0700663
John Reck61375a82014-09-18 19:27:48 +0000664 updateRootDisplayList(view, callbacks);
John Reckcec24ae2013-11-05 13:27:50 -0800665
John Reck119907c2014-08-14 09:02:01 -0700666 // register animating rendernodes which started animating prior to renderer
667 // creation, which is typical for animators started prior to first draw
668 if (attachInfo.mPendingAnimatingRenderNodes != null) {
669 final int count = attachInfo.mPendingAnimatingRenderNodes.size();
670 for (int i = 0; i < count; i++) {
671 registerAnimatingRenderNode(
672 attachInfo.mPendingAnimatingRenderNodes.get(i));
673 }
674 attachInfo.mPendingAnimatingRenderNodes.clear();
675 // We don't need this anymore as subsequent calls to
676 // ViewRootImpl#attachRenderNodeAnimator will go directly to us.
677 attachInfo.mPendingAnimatingRenderNodes = null;
678 }
679
John Reck8785ceb2018-10-29 16:45:58 -0700680 int syncResult = syncAndDrawFrame(choreographer.mFrameInfo);
John Reckaa95a882014-11-07 11:02:07 -0800681 if ((syncResult & SYNC_LOST_SURFACE_REWARD_IF_FOUND) != 0) {
682 setEnabled(false);
John Reckb13de072014-11-19 16:33:47 -0800683 attachInfo.mViewRootImpl.mSurface.release();
John Reckaa95a882014-11-07 11:02:07 -0800684 // Invalidate since we failed to draw. This should fetch a Surface
685 // if it is still needed or do nothing if we are no longer drawing
686 attachInfo.mViewRootImpl.invalidate();
687 }
John Reck8785ceb2018-10-29 16:45:58 -0700688 if ((syncResult & SYNC_REDRAW_REQUESTED) != 0) {
John Reckf9be7792014-05-02 18:21:16 -0700689 attachInfo.mViewRootImpl.invalidate();
690 }
John Reckcec24ae2013-11-05 13:27:50 -0800691 }
692
John Reckbb3a3582018-09-26 11:21:08 -0700693 /** The root of everything */
694 public @NonNull RenderNode getRootNode() {
695 return mRootNode;
696 }
697
Mihai Popa4bcd4d402018-02-07 17:13:51 +0000698 /**
699 * Basic synchronous renderer. Currently only used to render the Magnifier, so use with care.
700 * TODO: deduplicate against ThreadedRenderer.
701 *
702 * @hide
703 */
John Reck8785ceb2018-10-29 16:45:58 -0700704 public static class SimpleRenderer extends HardwareRenderer {
705 private final float mLightY, mLightZ, mLightRadius;
Mihai Popa4bcd4d402018-02-07 17:13:51 +0000706
707 public SimpleRenderer(final Context context, final String name, final Surface surface) {
John Reck8785ceb2018-10-29 16:45:58 -0700708 super();
709 setName(name);
710 setOpaque(false);
711 setSurface(surface);
Mihai Popa4bcd4d402018-02-07 17:13:51 +0000712 final TypedArray a = context.obtainStyledAttributes(null, R.styleable.Lighting, 0, 0);
713 mLightY = a.getDimension(R.styleable.Lighting_lightY, 0);
714 mLightZ = a.getDimension(R.styleable.Lighting_lightZ, 0);
John Reck8785ceb2018-10-29 16:45:58 -0700715 mLightRadius = a.getDimension(R.styleable.Lighting_lightRadius, 0);
Mihai Popa6dcd7282018-11-13 13:25:02 +0000716 final float ambientShadowAlpha = a.getFloat(R.styleable.Lighting_ambientShadowAlpha, 0);
717 final float spotShadowAlpha = a.getFloat(R.styleable.Lighting_spotShadowAlpha, 0);
Mihai Popa4bcd4d402018-02-07 17:13:51 +0000718 a.recycle();
John Reck8785ceb2018-10-29 16:45:58 -0700719 setLightSourceAlpha(ambientShadowAlpha, spotShadowAlpha);
Mihai Popa4bcd4d402018-02-07 17:13:51 +0000720 }
721
722 /**
723 * Set the light center.
724 */
725 public void setLightCenter(final Display display,
726 final int windowLeft, final int windowTop) {
727 // Adjust light position for window offsets.
728 final Point displaySize = new Point();
729 display.getRealSize(displaySize);
730 final float lightX = displaySize.x / 2f - windowLeft;
731 final float lightY = mLightY - windowTop;
732
John Reck8785ceb2018-10-29 16:45:58 -0700733 setLightSourceGeometry(lightX, lightY, mLightZ, mLightRadius);
Mihai Popa4bcd4d402018-02-07 17:13:51 +0000734 }
735
736 public RenderNode getRootNode() {
737 return mRootNode;
738 }
739
740 /**
741 * Draw the surface.
742 */
743 public void draw(final FrameDrawingCallback callback) {
744 final long vsync = AnimationUtils.currentAnimationTimeMillis() * 1000000L;
Mihai Popa4bcd4d402018-02-07 17:13:51 +0000745 if (callback != null) {
John Reck8785ceb2018-10-29 16:45:58 -0700746 setFrameCallback(callback);
Mihai Popa4bcd4d402018-02-07 17:13:51 +0000747 }
John Reckfe5dfca2019-01-17 17:01:32 -0800748 createRenderRequest()
749 .setVsyncTime(vsync)
750 .syncAndDraw();
Mihai Popa4bcd4d402018-02-07 17:13:51 +0000751 }
752 }
John Reckcec24ae2013-11-05 13:27:50 -0800753}