blob: e03f5faa26f2094bcf13944895fe89a6b40e4097 [file] [log] [blame]
Justin Klaassen10d07c82017-09-15 17:58:39 -04001/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.view;
18
19import android.annotation.IntDef;
20import android.annotation.NonNull;
21import android.app.ActivityManager;
22import android.content.Context;
23import android.content.res.TypedArray;
24import android.graphics.Bitmap;
25import android.graphics.Point;
26import android.graphics.Rect;
27import android.graphics.drawable.AnimatedVectorDrawable;
28import android.os.IBinder;
29import android.os.ParcelFileDescriptor;
30import android.os.RemoteException;
31import android.os.ServiceManager;
32import android.os.SystemProperties;
33import android.os.Trace;
34import android.util.Log;
35import android.view.Surface.OutOfResourcesException;
36import android.view.View.AttachInfo;
Justin Klaassen4d01eea2018-04-03 23:21:57 -040037import android.view.animation.AnimationUtils;
Justin Klaassen10d07c82017-09-15 17:58:39 -040038
39import com.android.internal.R;
40import com.android.internal.util.VirtualRefBasePtr;
41
42import java.io.File;
43import java.io.FileDescriptor;
44import java.io.PrintWriter;
45import java.lang.annotation.Retention;
46import java.lang.annotation.RetentionPolicy;
47
48/**
49 * Threaded renderer that proxies the rendering to a render thread. Most calls
50 * are currently synchronous.
51 *
52 * The UI thread can block on the RenderThread, but RenderThread must never
53 * block on the UI thread.
54 *
55 * ThreadedRenderer creates an instance of RenderProxy. RenderProxy in turn creates
56 * and manages a CanvasContext on the RenderThread. The CanvasContext is fully managed
57 * by the lifecycle of the RenderProxy.
58 *
59 * Note that although currently the EGL context & surfaces are created & managed
60 * by the render thread, the goal is to move that into a shared structure that can
61 * be managed by both threads. EGLSurface creation & deletion should ideally be
62 * done on the UI thread and not the RenderThread to avoid stalling the
63 * RenderThread with surface buffer allocation.
64 *
65 * @hide
66 */
67public final class ThreadedRenderer {
68 private static final String LOG_TAG = "ThreadedRenderer";
69
70 /**
71 * Name of the file that holds the shaders cache.
72 */
73 private static final String CACHE_PATH_SHADERS = "com.android.opengl.shaders_cache";
Justin Klaassen6a65f2d2017-11-17 16:38:15 -050074 private static final String CACHE_PATH_SKIASHADERS = "com.android.skia.shaders_cache";
Justin Klaassen10d07c82017-09-15 17:58:39 -040075
76 /**
77 * System property used to enable or disable threaded rendering profiling.
78 * The default value of this property is assumed to be false.
79 *
80 * When profiling is enabled, the adb shell dumpsys gfxinfo command will
81 * output extra information about the time taken to execute by the last
82 * frames.
83 *
84 * Possible values:
85 * "true", to enable profiling
86 * "visual_bars", to enable profiling and visualize the results on screen
87 * "false", to disable profiling
88 *
89 * @see #PROFILE_PROPERTY_VISUALIZE_BARS
90 *
91 * @hide
92 */
93 public static final String PROFILE_PROPERTY = "debug.hwui.profile";
94
95 /**
96 * Value for {@link #PROFILE_PROPERTY}. When the property is set to this
97 * value, profiling data will be visualized on screen as a bar chart.
98 *
99 * @hide
100 */
101 public static final String PROFILE_PROPERTY_VISUALIZE_BARS = "visual_bars";
102
103 /**
104 * System property used to specify the number of frames to be used
105 * when doing threaded rendering profiling.
106 * The default value of this property is #PROFILE_MAX_FRAMES.
107 *
108 * When profiling is enabled, the adb shell dumpsys gfxinfo command will
109 * output extra information about the time taken to execute by the last
110 * frames.
111 *
112 * Possible values:
113 * "60", to set the limit of frames to 60
114 */
115 static final String PROFILE_MAXFRAMES_PROPERTY = "debug.hwui.profile.maxframes";
116
117 /**
118 * System property used to debug EGL configuration choice.
119 *
120 * Possible values:
121 * "choice", print the chosen configuration only
122 * "all", print all possible configurations
123 */
124 static final String PRINT_CONFIG_PROPERTY = "debug.hwui.print_config";
125
126 /**
127 * Turn on to draw dirty regions every other frame.
128 *
129 * Possible values:
130 * "true", to enable dirty regions debugging
131 * "false", to disable dirty regions debugging
132 *
133 * @hide
134 */
135 public static final String DEBUG_DIRTY_REGIONS_PROPERTY = "debug.hwui.show_dirty_regions";
136
137 /**
138 * Turn on to flash hardware layers when they update.
139 *
140 * Possible values:
141 * "true", to enable hardware layers updates debugging
142 * "false", to disable hardware layers updates debugging
143 *
144 * @hide
145 */
146 public static final String DEBUG_SHOW_LAYERS_UPDATES_PROPERTY =
147 "debug.hwui.show_layers_updates";
148
149 /**
150 * Controls overdraw debugging.
151 *
152 * Possible values:
153 * "false", to disable overdraw debugging
154 * "show", to show overdraw areas on screen
155 * "count", to display an overdraw counter
156 *
157 * @hide
158 */
159 public static final String DEBUG_OVERDRAW_PROPERTY = "debug.hwui.overdraw";
160
161 /**
162 * Value for {@link #DEBUG_OVERDRAW_PROPERTY}. When the property is set to this
163 * value, overdraw will be shown on screen by coloring pixels.
164 *
165 * @hide
166 */
167 public static final String OVERDRAW_PROPERTY_SHOW = "show";
168
169 /**
Justin Klaassen10d07c82017-09-15 17:58:39 -0400170 * Turn on to debug non-rectangular clip operations.
171 *
172 * Possible values:
173 * "hide", to disable this debug mode
174 * "highlight", highlight drawing commands tested against a non-rectangular clip
175 * "stencil", renders the clip region on screen when set
176 *
177 * @hide
178 */
179 public static final String DEBUG_SHOW_NON_RECTANGULAR_CLIP_PROPERTY =
180 "debug.hwui.show_non_rect_clip";
181
Justin Klaassen98fe7812018-01-03 13:39:41 -0500182 /**
183 * Sets the FPS devisor to lower the FPS.
184 *
185 * Sets a positive integer as a divisor. 1 (the default value) menas the full FPS, and 2
186 * means half the full FPS.
187 *
188 *
189 * @hide
190 */
191 public static final String DEBUG_FPS_DIVISOR = "debug.hwui.fps_divisor";
192
Justin Klaassenb8042fc2018-04-15 00:41:15 -0400193 public static int EGL_CONTEXT_PRIORITY_HIGH_IMG = 0x3101;
194 public static int EGL_CONTEXT_PRIORITY_MEDIUM_IMG = 0x3102;
195 public static int EGL_CONTEXT_PRIORITY_LOW_IMG = 0x3103;
196
Justin Klaassen10d07c82017-09-15 17:58:39 -0400197 static {
198 // Try to check OpenGL support early if possible.
199 isAvailable();
200 }
201
202 /**
203 * A process can set this flag to false to prevent the use of threaded
204 * rendering.
205 *
206 * @hide
207 */
208 public static boolean sRendererDisabled = false;
209
210 /**
211 * Further threaded renderer disabling for the system process.
212 *
213 * @hide
214 */
215 public static boolean sSystemRendererDisabled = false;
216
217 /**
218 * Invoke this method to disable threaded rendering in the current process.
219 *
220 * @hide
221 */
222 public static void disable(boolean system) {
223 sRendererDisabled = true;
224 if (system) {
225 sSystemRendererDisabled = true;
226 }
227 }
228
229 public static boolean sTrimForeground = false;
230
231 /**
232 * Controls whether or not the renderer should aggressively trim
233 * memory. Note that this must not be set for any process that uses
234 * WebView! This should be only used by system_process or similar
235 * that do not go into the background.
236 */
237 public static void enableForegroundTrimming() {
238 sTrimForeground = true;
239 }
240
241 private static Boolean sSupportsOpenGL;
242
243 /**
244 * Indicates whether threaded rendering is available under any form for
245 * the view hierarchy.
246 *
247 * @return True if the view hierarchy can potentially be defer rendered,
248 * false otherwise
249 */
250 public static boolean isAvailable() {
251 if (sSupportsOpenGL != null) {
252 return sSupportsOpenGL.booleanValue();
253 }
254 if (SystemProperties.getInt("ro.kernel.qemu", 0) == 0) {
255 // Device is not an emulator.
256 sSupportsOpenGL = true;
257 return true;
258 }
259 int qemu_gles = SystemProperties.getInt("qemu.gles", -1);
260 if (qemu_gles == -1) {
261 // In this case, the value of the qemu.gles property is not ready
262 // because the SurfaceFlinger service may not start at this point.
263 return false;
264 }
265 // In the emulator this property will be set > 0 when OpenGL ES 2.0 is
266 // enabled, 0 otherwise. On old emulator versions it will be undefined.
267 sSupportsOpenGL = qemu_gles > 0;
268 return sSupportsOpenGL.booleanValue();
269 }
270
271 /**
272 * Sets the directory to use as a persistent storage for threaded rendering
273 * resources.
274 *
275 * @param cacheDir A directory the current process can write to
276 *
277 * @hide
278 */
279 public static void setupDiskCache(File cacheDir) {
Justin Klaassen6a65f2d2017-11-17 16:38:15 -0500280 ThreadedRenderer.setupShadersDiskCache(
281 new File(cacheDir, CACHE_PATH_SHADERS).getAbsolutePath(),
282 new File(cacheDir, CACHE_PATH_SKIASHADERS).getAbsolutePath());
Justin Klaassen10d07c82017-09-15 17:58:39 -0400283 }
284
285 /**
286 * Creates a threaded renderer using OpenGL.
287 *
288 * @param translucent True if the surface is translucent, false otherwise
289 *
290 * @return A threaded renderer backed by OpenGL.
291 */
292 public static ThreadedRenderer create(Context context, boolean translucent, String name) {
293 ThreadedRenderer renderer = null;
294 if (isAvailable()) {
295 renderer = new ThreadedRenderer(context, translucent, name);
296 }
297 return renderer;
298 }
299
300 /**
301 * Invoke this method when the system is running out of memory. This
302 * method will attempt to recover as much memory as possible, based on
303 * the specified hint.
304 *
305 * @param level Hint about the amount of memory that should be trimmed,
306 * see {@link android.content.ComponentCallbacks}
307 */
308 public static void trimMemory(int level) {
309 nTrimMemory(level);
310 }
311
312 public static void overrideProperty(@NonNull String name, @NonNull String value) {
313 if (name == null || value == null) {
314 throw new IllegalArgumentException("name and value must be non-null");
315 }
316 nOverrideProperty(name, value);
317 }
318
319 // Keep in sync with DrawFrameTask.h SYNC_* flags
320 // Nothing interesting to report
321 private static final int SYNC_OK = 0;
322 // Needs a ViewRoot invalidate
323 private static final int SYNC_INVALIDATE_REQUIRED = 1 << 0;
324 // Spoiler: the reward is GPU-accelerated drawing, better find that Surface!
325 private static final int SYNC_LOST_SURFACE_REWARD_IF_FOUND = 1 << 1;
326 // setStopped is true, drawing is false
327 // TODO: Remove this and SYNC_LOST_SURFACE_REWARD_IF_FOUND?
328 // This flag isn't really used as there's nothing that we care to do
329 // in response, so it really just exists to differentiate from LOST_SURFACE
330 // but possibly both can just be deleted.
331 private static final int SYNC_CONTEXT_IS_STOPPED = 1 << 2;
332
333 private static final String[] VISUALIZERS = {
334 PROFILE_PROPERTY_VISUALIZE_BARS,
335 };
336
337 private static final int FLAG_DUMP_FRAMESTATS = 1 << 0;
338 private static final int FLAG_DUMP_RESET = 1 << 1;
Justin Klaassen4d01eea2018-04-03 23:21:57 -0400339 private static final int FLAG_DUMP_ALL = FLAG_DUMP_FRAMESTATS;
Justin Klaassen10d07c82017-09-15 17:58:39 -0400340
Justin Klaassen98fe7812018-01-03 13:39:41 -0500341 @IntDef(flag = true, prefix = { "FLAG_DUMP_" }, value = {
342 FLAG_DUMP_FRAMESTATS,
343 FLAG_DUMP_RESET
344 })
Justin Klaassen10d07c82017-09-15 17:58:39 -0400345 @Retention(RetentionPolicy.SOURCE)
346 public @interface DumpFlags {}
347
348 // Size of the rendered content.
349 private int mWidth, mHeight;
350
351 // Actual size of the drawing surface.
352 private int mSurfaceWidth, mSurfaceHeight;
353
354 // Insets between the drawing surface and rendered content. These are
355 // applied as translation when updating the root render node.
356 private int mInsetTop, mInsetLeft;
357
358 // Whether the surface has insets. Used to protect opacity.
359 private boolean mHasInsets;
360
361 // Light and shadow properties specified by the theme.
362 private final float mLightY;
363 private final float mLightZ;
364 private final float mLightRadius;
365 private final int mAmbientShadowAlpha;
366 private final int mSpotShadowAlpha;
367
368 private long mNativeProxy;
369 private boolean mInitialized = false;
370 private RenderNode mRootNode;
371 private boolean mRootNodeNeedsUpdate;
372
373 private boolean mEnabled;
374 private boolean mRequested = true;
375 private boolean mIsOpaque = false;
376
377 ThreadedRenderer(Context context, boolean translucent, String name) {
378 final TypedArray a = context.obtainStyledAttributes(null, R.styleable.Lighting, 0, 0);
379 mLightY = a.getDimension(R.styleable.Lighting_lightY, 0);
380 mLightZ = a.getDimension(R.styleable.Lighting_lightZ, 0);
381 mLightRadius = a.getDimension(R.styleable.Lighting_lightRadius, 0);
382 mAmbientShadowAlpha =
383 (int) (255 * a.getFloat(R.styleable.Lighting_ambientShadowAlpha, 0) + 0.5f);
384 mSpotShadowAlpha = (int) (255 * a.getFloat(R.styleable.Lighting_spotShadowAlpha, 0) + 0.5f);
385 a.recycle();
386
387 long rootNodePtr = nCreateRootRenderNode();
388 mRootNode = RenderNode.adopt(rootNodePtr);
389 mRootNode.setClipToBounds(false);
390 mIsOpaque = !translucent;
391 mNativeProxy = nCreateProxy(translucent, rootNodePtr);
392 nSetName(mNativeProxy, name);
393
394 ProcessInitializer.sInstance.init(context, mNativeProxy);
395
396 loadSystemProperties();
397 }
398
399 /**
400 * Destroys the threaded rendering context.
401 */
402 void destroy() {
403 mInitialized = false;
404 updateEnabledState(null);
405 nDestroy(mNativeProxy, mRootNode.mNativeRenderNode);
406 }
407
408 /**
409 * Indicates whether threaded rendering is currently enabled.
410 *
411 * @return True if threaded rendering is in use, false otherwise.
412 */
413 boolean isEnabled() {
414 return mEnabled;
415 }
416
417 /**
418 * Indicates whether threaded rendering is currently enabled.
419 *
420 * @param enabled True if the threaded renderer is in use, false otherwise.
421 */
422 void setEnabled(boolean enabled) {
423 mEnabled = enabled;
424 }
425
426 /**
427 * Indicates whether threaded rendering is currently request but not
428 * necessarily enabled yet.
429 *
430 * @return True if requested, false otherwise.
431 */
432 boolean isRequested() {
433 return mRequested;
434 }
435
436 /**
437 * Indicates whether threaded rendering is currently requested but not
438 * necessarily enabled yet.
439 */
440 void setRequested(boolean requested) {
441 mRequested = requested;
442 }
443
444 private void updateEnabledState(Surface surface) {
445 if (surface == null || !surface.isValid()) {
446 setEnabled(false);
447 } else {
448 setEnabled(mInitialized);
449 }
450 }
451
452 /**
453 * Initializes the threaded renderer for the specified surface.
454 *
455 * @param surface The surface to render
456 *
457 * @return True if the initialization was successful, false otherwise.
458 */
459 boolean initialize(Surface surface) throws OutOfResourcesException {
460 boolean status = !mInitialized;
461 mInitialized = true;
462 updateEnabledState(surface);
463 nInitialize(mNativeProxy, surface);
464 return status;
465 }
466
467 /**
468 * Initializes the threaded renderer for the specified surface and setup the
469 * renderer for drawing, if needed. This is invoked when the ViewAncestor has
470 * potentially lost the threaded renderer. The threaded renderer should be
471 * reinitialized and setup when the render {@link #isRequested()} and
472 * {@link #isEnabled()}.
473 *
474 * @param width The width of the drawing surface.
475 * @param height The height of the drawing surface.
476 * @param attachInfo Information about the window.
477 * @param surface The surface to render
478 * @param surfaceInsets The drawing surface insets to apply
479 *
480 * @return true if the surface was initialized, false otherwise. Returning
481 * false might mean that the surface was already initialized.
482 */
483 boolean initializeIfNeeded(int width, int height, View.AttachInfo attachInfo,
484 Surface surface, Rect surfaceInsets) throws OutOfResourcesException {
485 if (isRequested()) {
486 // We lost the gl context, so recreate it.
487 if (!isEnabled()) {
488 if (initialize(surface)) {
489 setup(width, height, attachInfo, surfaceInsets);
490 return true;
491 }
492 }
493 }
494 return false;
495 }
496
497 /**
498 * Updates the threaded renderer for the specified surface.
499 *
500 * @param surface The surface to render
501 */
502 void updateSurface(Surface surface) throws OutOfResourcesException {
503 updateEnabledState(surface);
504 nUpdateSurface(mNativeProxy, surface);
505 }
506
507 /**
508 * Halts any current rendering into the surface. Use this if it is unclear whether
509 * or not the surface used by the ThreadedRenderer will be changing. It
510 * Suspends any rendering into the surface, but will not do any destruction.
511 *
512 * Any subsequent draws will override the pause, resuming normal operation.
513 */
514 boolean pauseSurface(Surface surface) {
515 return nPauseSurface(mNativeProxy, surface);
516 }
517
518 /**
519 * Hard stops or resumes rendering into the surface. This flag is used to
520 * determine whether or not it is safe to use the given surface *at all*
521 */
522 void setStopped(boolean stopped) {
523 nSetStopped(mNativeProxy, stopped);
524 }
525
526 /**
527 * Destroys all hardware rendering resources associated with the specified
528 * view hierarchy.
529 *
530 * @param view The root of the view hierarchy
531 */
532 void destroyHardwareResources(View view) {
533 destroyResources(view);
534 nDestroyHardwareResources(mNativeProxy);
535 }
536
537 private static void destroyResources(View view) {
538 view.destroyHardwareResources();
539 }
540
541 /**
542 * Detaches the layer's surface texture from the GL context and releases
543 * the texture id
544 */
545 void detachSurfaceTexture(long hardwareLayer) {
546 nDetachSurfaceTexture(mNativeProxy, hardwareLayer);
547 }
548
549 /**
550 * Sets up the renderer for drawing.
551 *
552 * @param width The width of the drawing surface.
553 * @param height The height of the drawing surface.
554 * @param attachInfo Information about the window.
555 * @param surfaceInsets The drawing surface insets to apply
556 */
557 void setup(int width, int height, AttachInfo attachInfo, Rect surfaceInsets) {
558 mWidth = width;
559 mHeight = height;
560
561 if (surfaceInsets != null && (surfaceInsets.left != 0 || surfaceInsets.right != 0
562 || surfaceInsets.top != 0 || surfaceInsets.bottom != 0)) {
563 mHasInsets = true;
564 mInsetLeft = surfaceInsets.left;
565 mInsetTop = surfaceInsets.top;
566 mSurfaceWidth = width + mInsetLeft + surfaceInsets.right;
567 mSurfaceHeight = height + mInsetTop + surfaceInsets.bottom;
568
569 // If the surface has insets, it can't be opaque.
570 setOpaque(false);
571 } else {
572 mHasInsets = false;
573 mInsetLeft = 0;
574 mInsetTop = 0;
575 mSurfaceWidth = width;
576 mSurfaceHeight = height;
577 }
578
579 mRootNode.setLeftTopRightBottom(-mInsetLeft, -mInsetTop, mSurfaceWidth, mSurfaceHeight);
580 nSetup(mNativeProxy, mLightRadius,
581 mAmbientShadowAlpha, mSpotShadowAlpha);
582
583 setLightCenter(attachInfo);
584 }
585
586 /**
587 * Updates the light position based on the position of the window.
588 *
589 * @param attachInfo Information about the window.
590 */
591 void setLightCenter(AttachInfo attachInfo) {
592 // Adjust light position for window offsets.
593 final Point displaySize = attachInfo.mPoint;
594 attachInfo.mDisplay.getRealSize(displaySize);
595 final float lightX = displaySize.x / 2f - attachInfo.mWindowLeft;
596 final float lightY = mLightY - attachInfo.mWindowTop;
597
598 nSetLightCenter(mNativeProxy, lightX, lightY, mLightZ);
599 }
600
601 /**
602 * Change the ThreadedRenderer's opacity
603 */
604 void setOpaque(boolean opaque) {
605 mIsOpaque = opaque && !mHasInsets;
606 nSetOpaque(mNativeProxy, mIsOpaque);
607 }
608
609 boolean isOpaque() {
610 return mIsOpaque;
611 }
612
613 /**
614 * Enable/disable wide gamut rendering on this renderer.
615 */
616 void setWideGamut(boolean wideGamut) {
617 nSetWideGamut(mNativeProxy, wideGamut);
618 }
619
620 /**
621 * Gets the current width of the surface. This is the width that the surface
622 * was last set to in a call to {@link #setup(int, int, View.AttachInfo, Rect)}.
623 *
624 * @return the current width of the surface
625 */
626 int getWidth() {
627 return mWidth;
628 }
629
630 /**
631 * Gets the current height of the surface. This is the height that the surface
632 * was last set to in a call to {@link #setup(int, int, View.AttachInfo, Rect)}.
633 *
634 * @return the current width of the surface
635 */
636 int getHeight() {
637 return mHeight;
638 }
639
640 /**
641 * Outputs extra debugging information in the specified file descriptor.
642 */
643 void dumpGfxInfo(PrintWriter pw, FileDescriptor fd, String[] args) {
644 pw.flush();
Justin Klaassen4d01eea2018-04-03 23:21:57 -0400645 // If there's no arguments, eg 'dumpsys gfxinfo', then dump everything.
646 // If there's a targetted package, eg 'dumpsys gfxinfo com.android.systemui', then only
647 // dump the summary information
648 int flags = (args == null || args.length == 0) ? FLAG_DUMP_ALL : 0;
Justin Klaassen10d07c82017-09-15 17:58:39 -0400649 for (int i = 0; i < args.length; i++) {
650 switch (args[i]) {
651 case "framestats":
652 flags |= FLAG_DUMP_FRAMESTATS;
653 break;
654 case "reset":
655 flags |= FLAG_DUMP_RESET;
656 break;
Justin Klaassen4d01eea2018-04-03 23:21:57 -0400657 case "-a": // magic option passed when dumping a bugreport.
658 flags = FLAG_DUMP_ALL;
659 break;
Justin Klaassen10d07c82017-09-15 17:58:39 -0400660 }
661 }
662 nDumpProfileInfo(mNativeProxy, fd, flags);
663 }
664
665 /**
666 * Loads system properties used by the renderer. This method is invoked
667 * whenever system properties are modified. Implementations can use this
668 * to trigger live updates of the renderer based on properties.
669 *
670 * @return True if a property has changed.
671 */
672 boolean loadSystemProperties() {
673 boolean changed = nLoadSystemProperties(mNativeProxy);
674 if (changed) {
675 invalidateRoot();
676 }
677 return changed;
678 }
679
680 private void updateViewTreeDisplayList(View view) {
681 view.mPrivateFlags |= View.PFLAG_DRAWN;
682 view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
683 == View.PFLAG_INVALIDATED;
684 view.mPrivateFlags &= ~View.PFLAG_INVALIDATED;
685 view.updateDisplayListIfDirty();
686 view.mRecreateDisplayList = false;
687 }
688
689 private void updateRootDisplayList(View view, DrawCallbacks callbacks) {
690 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Record View#draw()");
691 updateViewTreeDisplayList(view);
692
693 if (mRootNodeNeedsUpdate || !mRootNode.isValid()) {
694 DisplayListCanvas canvas = mRootNode.start(mSurfaceWidth, mSurfaceHeight);
695 try {
696 final int saveCount = canvas.save();
697 canvas.translate(mInsetLeft, mInsetTop);
698 callbacks.onPreDraw(canvas);
699
700 canvas.insertReorderBarrier();
701 canvas.drawRenderNode(view.updateDisplayListIfDirty());
702 canvas.insertInorderBarrier();
703
704 callbacks.onPostDraw(canvas);
705 canvas.restoreToCount(saveCount);
706 mRootNodeNeedsUpdate = false;
707 } finally {
708 mRootNode.end(canvas);
709 }
710 }
711 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
712 }
713
714 /**
715 * Adds a rendernode to the renderer which can be drawn and changed asynchronously to the
716 * rendernode of the UI thread.
717 * @param node The node to add.
718 * @param placeFront If true, the render node will be placed in front of the content node,
719 * otherwise behind the content node.
720 */
721 public void addRenderNode(RenderNode node, boolean placeFront) {
722 nAddRenderNode(mNativeProxy, node.mNativeRenderNode, placeFront);
723 }
724
725 /**
726 * Only especially added render nodes can be removed.
727 * @param node The node which was added via addRenderNode which should get removed again.
728 */
729 public void removeRenderNode(RenderNode node) {
730 nRemoveRenderNode(mNativeProxy, node.mNativeRenderNode);
731 }
732
733 /**
734 * Draws a particular render node. If the node is not the content node, only the additional
735 * nodes will get drawn and the content remains untouched.
736 * @param node The node to be drawn.
737 */
738 public void drawRenderNode(RenderNode node) {
739 nDrawRenderNode(mNativeProxy, node.mNativeRenderNode);
740 }
741
742 /**
743 * To avoid unnecessary overdrawing of the main content all additionally passed render nodes
744 * will be prevented to overdraw this area. It will be synchronized with the draw call.
745 * This should be updated in the content view's draw call.
746 * @param left The left side of the protected bounds.
747 * @param top The top side of the protected bounds.
748 * @param right The right side of the protected bounds.
749 * @param bottom The bottom side of the protected bounds.
750 */
751 public void setContentDrawBounds(int left, int top, int right, int bottom) {
752 nSetContentDrawBounds(mNativeProxy, left, top, right, bottom);
753 }
754
755 /**
756 * Interface used to receive callbacks whenever a view is drawn by
757 * a threaded renderer instance.
758 */
759 interface DrawCallbacks {
760 /**
761 * Invoked before a view is drawn by a threaded renderer.
762 * This method can be used to apply transformations to the
763 * canvas but no drawing command should be issued.
764 *
765 * @param canvas The Canvas used to render the view.
766 */
767 void onPreDraw(DisplayListCanvas canvas);
768
769 /**
770 * Invoked after a view is drawn by a threaded renderer.
771 * It is safe to invoke drawing commands from this method.
772 *
773 * @param canvas The Canvas used to render the view.
774 */
775 void onPostDraw(DisplayListCanvas canvas);
776 }
777
778 /**
779 * Indicates that the content drawn by DrawCallbacks needs to
780 * be updated, which will be done by the next call to draw()
781 */
782 void invalidateRoot() {
783 mRootNodeNeedsUpdate = true;
784 }
785
786 /**
787 * Draws the specified view.
788 *
789 * @param view The view to draw.
790 * @param attachInfo AttachInfo tied to the specified view.
791 * @param callbacks Callbacks invoked when drawing happens.
792 */
793 void draw(View view, AttachInfo attachInfo, DrawCallbacks callbacks) {
794 attachInfo.mIgnoreDirtyState = true;
795
796 final Choreographer choreographer = attachInfo.mViewRootImpl.mChoreographer;
797 choreographer.mFrameInfo.markDrawStart();
798
799 updateRootDisplayList(view, callbacks);
800
801 attachInfo.mIgnoreDirtyState = false;
802
803 // register animating rendernodes which started animating prior to renderer
804 // creation, which is typical for animators started prior to first draw
805 if (attachInfo.mPendingAnimatingRenderNodes != null) {
806 final int count = attachInfo.mPendingAnimatingRenderNodes.size();
807 for (int i = 0; i < count; i++) {
808 registerAnimatingRenderNode(
809 attachInfo.mPendingAnimatingRenderNodes.get(i));
810 }
811 attachInfo.mPendingAnimatingRenderNodes.clear();
812 // We don't need this anymore as subsequent calls to
813 // ViewRootImpl#attachRenderNodeAnimator will go directly to us.
814 attachInfo.mPendingAnimatingRenderNodes = null;
815 }
816
817 final long[] frameInfo = choreographer.mFrameInfo.mFrameInfo;
818 int syncResult = nSyncAndDrawFrame(mNativeProxy, frameInfo, frameInfo.length);
819 if ((syncResult & SYNC_LOST_SURFACE_REWARD_IF_FOUND) != 0) {
820 setEnabled(false);
821 attachInfo.mViewRootImpl.mSurface.release();
822 // Invalidate since we failed to draw. This should fetch a Surface
823 // if it is still needed or do nothing if we are no longer drawing
824 attachInfo.mViewRootImpl.invalidate();
825 }
826 if ((syncResult & SYNC_INVALIDATE_REQUIRED) != 0) {
827 attachInfo.mViewRootImpl.invalidate();
828 }
829 }
830
831 static void invokeFunctor(long functor, boolean waitForCompletion) {
832 nInvokeFunctor(functor, waitForCompletion);
833 }
834
835 /**
836 * Creates a new hardware layer. A hardware layer built by calling this
837 * method will be treated as a texture layer, instead of as a render target.
838 *
839 * @return A hardware layer
840 */
Justin Klaassen4d01eea2018-04-03 23:21:57 -0400841 TextureLayer createTextureLayer() {
Justin Klaassen10d07c82017-09-15 17:58:39 -0400842 long layer = nCreateTextureLayer(mNativeProxy);
Justin Klaassen4d01eea2018-04-03 23:21:57 -0400843 return TextureLayer.adoptTextureLayer(this, layer);
Justin Klaassen10d07c82017-09-15 17:58:39 -0400844 }
845
846
847 void buildLayer(RenderNode node) {
848 nBuildLayer(mNativeProxy, node.getNativeDisplayList());
849 }
850
851
Justin Klaassen4d01eea2018-04-03 23:21:57 -0400852 boolean copyLayerInto(final TextureLayer layer, final Bitmap bitmap) {
Justin Klaassen10d07c82017-09-15 17:58:39 -0400853 return nCopyLayerInto(mNativeProxy,
854 layer.getDeferredLayerUpdater(), bitmap);
855 }
856
857 /**
858 * Indicates that the specified hardware layer needs to be updated
859 * as soon as possible.
860 *
861 * @param layer The hardware layer that needs an update
862 */
Justin Klaassen4d01eea2018-04-03 23:21:57 -0400863 void pushLayerUpdate(TextureLayer layer) {
Justin Klaassen10d07c82017-09-15 17:58:39 -0400864 nPushLayerUpdate(mNativeProxy, layer.getDeferredLayerUpdater());
865 }
866
867 /**
868 * Tells the HardwareRenderer that the layer is destroyed. The renderer
869 * should remove the layer from any update queues.
870 */
Justin Klaassen4d01eea2018-04-03 23:21:57 -0400871 void onLayerDestroyed(TextureLayer layer) {
Justin Klaassen10d07c82017-09-15 17:58:39 -0400872 nCancelLayerUpdate(mNativeProxy, layer.getDeferredLayerUpdater());
873 }
874
875 /**
876 * Blocks until all previously queued work has completed.
877 */
878 void fence() {
879 nFence(mNativeProxy);
880 }
881
882 /**
883 * Prevents any further drawing until draw() is called. This is a signal
884 * that the contents of the RenderNode tree are no longer safe to play back.
885 * In practice this usually means that there are Functor pointers in the
886 * display list that are no longer valid.
887 */
888 void stopDrawing() {
889 nStopDrawing(mNativeProxy);
890 }
891
892 /**
893 * Called by {@link ViewRootImpl} when a new performTraverals is scheduled.
894 */
895 public void notifyFramePending() {
896 nNotifyFramePending(mNativeProxy);
897 }
898
899
900 void registerAnimatingRenderNode(RenderNode animator) {
901 nRegisterAnimatingRenderNode(mRootNode.mNativeRenderNode, animator.mNativeRenderNode);
902 }
903
904 void registerVectorDrawableAnimator(
905 AnimatedVectorDrawable.VectorDrawableAnimatorRT animator) {
906 nRegisterVectorDrawableAnimator(mRootNode.mNativeRenderNode,
907 animator.getAnimatorNativePtr());
908 }
909
910 public void serializeDisplayListTree() {
911 nSerializeDisplayListTree(mNativeProxy);
912 }
913
914 public static int copySurfaceInto(Surface surface, Rect srcRect, Bitmap bitmap) {
915 if (srcRect == null) {
916 // Empty rect means entire surface
917 return nCopySurfaceInto(surface, 0, 0, 0, 0, bitmap);
918 } else {
919 return nCopySurfaceInto(surface, srcRect.left, srcRect.top,
920 srcRect.right, srcRect.bottom, bitmap);
921 }
922 }
923
924 /**
925 * Creates a {@link android.graphics.Bitmap.Config#HARDWARE} bitmap from the given
926 * RenderNode. Note that the RenderNode should be created as a root node (so x/y of 0,0), and
927 * not the RenderNode from a View.
928 **/
929 public static Bitmap createHardwareBitmap(RenderNode node, int width, int height) {
930 return nCreateHardwareBitmap(node.getNativeDisplayList(), width, height);
931 }
932
933 /**
934 * Sets whether or not high contrast text rendering is enabled. The setting is global
935 * but only affects content rendered after the change is made.
936 */
937 public static void setHighContrastText(boolean highContrastText) {
938 nSetHighContrastText(highContrastText);
939 }
940
Justin Klaassen4d01eea2018-04-03 23:21:57 -0400941 /**
942 * If set RenderThread will avoid doing any IPC using instead a fake vsync & DisplayInfo source
943 */
944 public static void setIsolatedProcess(boolean isIsolated) {
945 nSetIsolatedProcess(isIsolated);
946 }
947
948 /**
949 * If set extra graphics debugging abilities will be enabled such as dumping skp
950 */
951 public static void setDebuggingEnabled(boolean enable) {
952 nSetDebuggingEnabled(enable);
953 }
954
Justin Klaassen10d07c82017-09-15 17:58:39 -0400955 @Override
956 protected void finalize() throws Throwable {
957 try {
958 nDeleteProxy(mNativeProxy);
959 mNativeProxy = 0;
960 } finally {
961 super.finalize();
962 }
963 }
964
Justin Klaassen4d01eea2018-04-03 23:21:57 -0400965 /**
966 * Basic synchronous renderer. Currently only used to render the Magnifier, so use with care.
967 * TODO: deduplicate against ThreadedRenderer.
968 *
969 * @hide
970 */
971 public static class SimpleRenderer {
972 private final RenderNode mRootNode;
973 private long mNativeProxy;
974 private final float mLightY, mLightZ;
975 private Surface mSurface;
976 private final FrameInfo mFrameInfo = new FrameInfo();
977
978 public SimpleRenderer(final Context context, final String name, final Surface surface) {
979 final TypedArray a = context.obtainStyledAttributes(null, R.styleable.Lighting, 0, 0);
980 mLightY = a.getDimension(R.styleable.Lighting_lightY, 0);
981 mLightZ = a.getDimension(R.styleable.Lighting_lightZ, 0);
982 final float lightRadius = a.getDimension(R.styleable.Lighting_lightRadius, 0);
983 final int ambientShadowAlpha =
984 (int) (255 * a.getFloat(R.styleable.Lighting_ambientShadowAlpha, 0) + 0.5f);
985 final int spotShadowAlpha =
986 (int) (255 * a.getFloat(R.styleable.Lighting_spotShadowAlpha, 0) + 0.5f);
987 a.recycle();
988
989 final long rootNodePtr = nCreateRootRenderNode();
990 mRootNode = RenderNode.adopt(rootNodePtr);
991 mRootNode.setClipToBounds(false);
992 mNativeProxy = nCreateProxy(true /* translucent */, rootNodePtr);
993 nSetName(mNativeProxy, name);
994
995 ProcessInitializer.sInstance.init(context, mNativeProxy);
996 nLoadSystemProperties(mNativeProxy);
997
998 nSetup(mNativeProxy, lightRadius, ambientShadowAlpha, spotShadowAlpha);
999
1000 mSurface = surface;
1001 nUpdateSurface(mNativeProxy, surface);
1002 }
1003
1004 /**
1005 * Set the light center.
1006 */
1007 public void setLightCenter(final Display display,
1008 final int windowLeft, final int windowTop) {
1009 // Adjust light position for window offsets.
1010 final Point displaySize = new Point();
1011 display.getRealSize(displaySize);
1012 final float lightX = displaySize.x / 2f - windowLeft;
1013 final float lightY = mLightY - windowTop;
1014
1015 nSetLightCenter(mNativeProxy, lightX, lightY, mLightZ);
1016 }
1017
1018 public RenderNode getRootNode() {
1019 return mRootNode;
1020 }
1021
1022 /**
1023 * Draw the surface.
1024 */
1025 public void draw(final FrameDrawingCallback callback) {
1026 final long vsync = AnimationUtils.currentAnimationTimeMillis() * 1000000L;
1027 mFrameInfo.setVsync(vsync, vsync);
1028 mFrameInfo.addFlags(1 << 2 /* VSYNC */);
1029 if (callback != null) {
1030 nSetFrameCallback(mNativeProxy, callback);
1031 }
1032 nSyncAndDrawFrame(mNativeProxy, mFrameInfo.mFrameInfo, mFrameInfo.mFrameInfo.length);
1033 }
1034
1035 /**
1036 * Destroy the renderer.
1037 */
1038 public void destroy() {
1039 mSurface = null;
1040 nDestroy(mNativeProxy, mRootNode.mNativeRenderNode);
1041 }
1042
1043 @Override
1044 protected void finalize() throws Throwable {
1045 try {
1046 nDeleteProxy(mNativeProxy);
1047 mNativeProxy = 0;
1048 } finally {
1049 super.finalize();
1050 }
1051 }
1052 }
1053
1054 /**
1055 * Interface used to receive callbacks when a frame is being drawn.
1056 */
1057 public interface FrameDrawingCallback {
1058 /**
1059 * Invoked during a frame drawing.
1060 *
1061 * @param frame The id of the frame being drawn.
1062 */
1063 void onFrameDraw(long frame);
1064 }
1065
Justin Klaassen10d07c82017-09-15 17:58:39 -04001066 private static class ProcessInitializer {
1067 static ProcessInitializer sInstance = new ProcessInitializer();
1068
1069 private boolean mInitialized = false;
1070
1071 private Context mAppContext;
1072 private IGraphicsStats mGraphicsStatsService;
1073 private IGraphicsStatsCallback mGraphicsStatsCallback = new IGraphicsStatsCallback.Stub() {
1074 @Override
1075 public void onRotateGraphicsStatsBuffer() throws RemoteException {
1076 rotateBuffer();
1077 }
1078 };
1079
1080 private ProcessInitializer() {}
1081
1082 synchronized void init(Context context, long renderProxy) {
1083 if (mInitialized) return;
1084 mInitialized = true;
1085 mAppContext = context.getApplicationContext();
Justin Klaassen98fe7812018-01-03 13:39:41 -05001086
Justin Klaassen10d07c82017-09-15 17:58:39 -04001087 initSched(renderProxy);
Justin Klaassen4d01eea2018-04-03 23:21:57 -04001088
1089 if (mAppContext != null) {
1090 initGraphicsStats();
1091 }
Justin Klaassen10d07c82017-09-15 17:58:39 -04001092 }
1093
1094 private void initSched(long renderProxy) {
1095 try {
1096 int tid = nGetRenderThreadTid(renderProxy);
1097 ActivityManager.getService().setRenderThread(tid);
1098 } catch (Throwable t) {
1099 Log.w(LOG_TAG, "Failed to set scheduler for RenderThread", t);
1100 }
1101 }
1102
1103 private void initGraphicsStats() {
1104 try {
1105 IBinder binder = ServiceManager.getService("graphicsstats");
1106 if (binder == null) return;
1107 mGraphicsStatsService = IGraphicsStats.Stub.asInterface(binder);
1108 requestBuffer();
1109 } catch (Throwable t) {
1110 Log.w(LOG_TAG, "Could not acquire gfx stats buffer", t);
1111 }
1112 }
1113
1114 private void rotateBuffer() {
1115 nRotateProcessStatsBuffer();
1116 requestBuffer();
1117 }
1118
1119 private void requestBuffer() {
1120 try {
1121 final String pkg = mAppContext.getApplicationInfo().packageName;
1122 ParcelFileDescriptor pfd = mGraphicsStatsService
1123 .requestBufferForProcess(pkg, mGraphicsStatsCallback);
1124 nSetProcessStatsBuffer(pfd.getFd());
1125 pfd.close();
1126 } catch (Throwable t) {
1127 Log.w(LOG_TAG, "Could not acquire gfx stats buffer", t);
1128 }
1129 }
1130 }
1131
1132 void addFrameMetricsObserver(FrameMetricsObserver observer) {
1133 long nativeObserver = nAddFrameMetricsObserver(mNativeProxy, observer);
1134 observer.mNative = new VirtualRefBasePtr(nativeObserver);
1135 }
1136
1137 void removeFrameMetricsObserver(FrameMetricsObserver observer) {
1138 nRemoveFrameMetricsObserver(mNativeProxy, observer.mNative.get());
1139 observer.mNative = null;
1140 }
1141
Justin Klaassen98fe7812018-01-03 13:39:41 -05001142 /** b/68769804: For low FPS experiments. */
1143 public static void setFPSDivisor(int divisor) {
Jeff Davidsona192cc22018-02-08 15:30:06 -08001144 nHackySetRTAnimationsEnabled(divisor <= 1);
Justin Klaassen98fe7812018-01-03 13:39:41 -05001145 }
1146
Justin Klaassenb8042fc2018-04-15 00:41:15 -04001147 /**
1148 * Changes the OpenGL context priority if IMG_context_priority extension is available. Must be
1149 * called before any OpenGL context is created.
1150 *
1151 * @param priority The priority to use. Must be one of EGL_CONTEXT_PRIORITY_* values.
1152 */
1153 public static void setContextPriority(int priority) {
1154 nSetContextPriority(priority);
1155 }
1156
Justin Klaassen10d07c82017-09-15 17:58:39 -04001157 /** Not actually public - internal use only. This doc to make lint happy */
1158 public static native void disableVsync();
1159
Justin Klaassen6a65f2d2017-11-17 16:38:15 -05001160 static native void setupShadersDiskCache(String cacheFile, String skiaCacheFile);
Justin Klaassen10d07c82017-09-15 17:58:39 -04001161
1162 private static native void nRotateProcessStatsBuffer();
1163 private static native void nSetProcessStatsBuffer(int fd);
1164 private static native int nGetRenderThreadTid(long nativeProxy);
1165
1166 private static native long nCreateRootRenderNode();
1167 private static native long nCreateProxy(boolean translucent, long rootRenderNode);
1168 private static native void nDeleteProxy(long nativeProxy);
1169
1170 private static native boolean nLoadSystemProperties(long nativeProxy);
1171 private static native void nSetName(long nativeProxy, String name);
1172
1173 private static native void nInitialize(long nativeProxy, Surface window);
1174 private static native void nUpdateSurface(long nativeProxy, Surface window);
1175 private static native boolean nPauseSurface(long nativeProxy, Surface window);
1176 private static native void nSetStopped(long nativeProxy, boolean stopped);
1177 private static native void nSetup(long nativeProxy,
1178 float lightRadius, int ambientShadowAlpha, int spotShadowAlpha);
1179 private static native void nSetLightCenter(long nativeProxy,
1180 float lightX, float lightY, float lightZ);
1181 private static native void nSetOpaque(long nativeProxy, boolean opaque);
1182 private static native void nSetWideGamut(long nativeProxy, boolean wideGamut);
1183 private static native int nSyncAndDrawFrame(long nativeProxy, long[] frameInfo, int size);
1184 private static native void nDestroy(long nativeProxy, long rootRenderNode);
1185 private static native void nRegisterAnimatingRenderNode(long rootRenderNode, long animatingNode);
1186 private static native void nRegisterVectorDrawableAnimator(long rootRenderNode, long animator);
1187
1188 private static native void nInvokeFunctor(long functor, boolean waitForCompletion);
1189
1190 private static native long nCreateTextureLayer(long nativeProxy);
1191 private static native void nBuildLayer(long nativeProxy, long node);
1192 private static native boolean nCopyLayerInto(long nativeProxy, long layer, Bitmap bitmap);
1193 private static native void nPushLayerUpdate(long nativeProxy, long layer);
1194 private static native void nCancelLayerUpdate(long nativeProxy, long layer);
1195 private static native void nDetachSurfaceTexture(long nativeProxy, long layer);
1196
1197 private static native void nDestroyHardwareResources(long nativeProxy);
1198 private static native void nTrimMemory(int level);
1199 private static native void nOverrideProperty(String name, String value);
1200
1201 private static native void nFence(long nativeProxy);
1202 private static native void nStopDrawing(long nativeProxy);
1203 private static native void nNotifyFramePending(long nativeProxy);
1204
1205 private static native void nSerializeDisplayListTree(long nativeProxy);
1206
1207 private static native void nDumpProfileInfo(long nativeProxy, FileDescriptor fd,
1208 @DumpFlags int dumpFlags);
1209
1210 private static native void nAddRenderNode(long nativeProxy, long rootRenderNode,
1211 boolean placeFront);
1212 private static native void nRemoveRenderNode(long nativeProxy, long rootRenderNode);
1213 private static native void nDrawRenderNode(long nativeProxy, long rootRenderNode);
1214 private static native void nSetContentDrawBounds(long nativeProxy, int left,
1215 int top, int right, int bottom);
Justin Klaassen4d01eea2018-04-03 23:21:57 -04001216 private static native void nSetFrameCallback(long nativeProxy, FrameDrawingCallback callback);
Justin Klaassen10d07c82017-09-15 17:58:39 -04001217
1218 private static native long nAddFrameMetricsObserver(long nativeProxy, FrameMetricsObserver observer);
1219 private static native void nRemoveFrameMetricsObserver(long nativeProxy, long nativeObserver);
1220
1221 private static native int nCopySurfaceInto(Surface surface,
1222 int srcLeft, int srcTop, int srcRight, int srcBottom, Bitmap bitmap);
1223
1224 private static native Bitmap nCreateHardwareBitmap(long renderNode, int width, int height);
1225 private static native void nSetHighContrastText(boolean enabled);
Justin Klaassen98fe7812018-01-03 13:39:41 -05001226 // For temporary experimentation b/66945974
1227 private static native void nHackySetRTAnimationsEnabled(boolean enabled);
Justin Klaassen4d01eea2018-04-03 23:21:57 -04001228 private static native void nSetDebuggingEnabled(boolean enabled);
1229 private static native void nSetIsolatedProcess(boolean enabled);
Justin Klaassenb8042fc2018-04-15 00:41:15 -04001230 private static native void nSetContextPriority(int priority);
Justin Klaassen10d07c82017-09-15 17:58:39 -04001231}