ThreadedRenderer.java revision 64be98d5d27a2a2b786e28ae7afbff5ac987f163
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
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;
37import android.view.animation.AnimationUtils;
38
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";
74    private static final String CACHE_PATH_SKIASHADERS = "com.android.skia.shaders_cache";
75
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    /**
170     * 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
182    /**
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
193    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
197    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) {
280        ThreadedRenderer.setupShadersDiskCache(
281                new File(cacheDir, CACHE_PATH_SHADERS).getAbsolutePath(),
282                new File(cacheDir, CACHE_PATH_SKIASHADERS).getAbsolutePath());
283    }
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;
339    private static final int FLAG_DUMP_ALL          = FLAG_DUMP_FRAMESTATS;
340
341    @IntDef(flag = true, prefix = { "FLAG_DUMP_" }, value = {
342            FLAG_DUMP_FRAMESTATS,
343            FLAG_DUMP_RESET
344    })
345    @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();
645        // 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;
649        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;
657                case "-a": // magic option passed when dumping a bugreport.
658                    flags = FLAG_DUMP_ALL;
659                    break;
660            }
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            FrameDrawingCallback frameDrawingCallback) {
795        attachInfo.mIgnoreDirtyState = true;
796
797        final Choreographer choreographer = attachInfo.mViewRootImpl.mChoreographer;
798        choreographer.mFrameInfo.markDrawStart();
799
800        updateRootDisplayList(view, callbacks);
801
802        attachInfo.mIgnoreDirtyState = false;
803
804        // register animating rendernodes which started animating prior to renderer
805        // creation, which is typical for animators started prior to first draw
806        if (attachInfo.mPendingAnimatingRenderNodes != null) {
807            final int count = attachInfo.mPendingAnimatingRenderNodes.size();
808            for (int i = 0; i < count; i++) {
809                registerAnimatingRenderNode(
810                        attachInfo.mPendingAnimatingRenderNodes.get(i));
811            }
812            attachInfo.mPendingAnimatingRenderNodes.clear();
813            // We don't need this anymore as subsequent calls to
814            // ViewRootImpl#attachRenderNodeAnimator will go directly to us.
815            attachInfo.mPendingAnimatingRenderNodes = null;
816        }
817
818        final long[] frameInfo = choreographer.mFrameInfo.mFrameInfo;
819        if (frameDrawingCallback != null) {
820            nSetFrameCallback(mNativeProxy, frameDrawingCallback);
821        }
822        int syncResult = nSyncAndDrawFrame(mNativeProxy, frameInfo, frameInfo.length);
823        if ((syncResult & SYNC_LOST_SURFACE_REWARD_IF_FOUND) != 0) {
824            setEnabled(false);
825            attachInfo.mViewRootImpl.mSurface.release();
826            // Invalidate since we failed to draw. This should fetch a Surface
827            // if it is still needed or do nothing if we are no longer drawing
828            attachInfo.mViewRootImpl.invalidate();
829        }
830        if ((syncResult & SYNC_INVALIDATE_REQUIRED) != 0) {
831            attachInfo.mViewRootImpl.invalidate();
832        }
833    }
834
835    static void invokeFunctor(long functor, boolean waitForCompletion) {
836        nInvokeFunctor(functor, waitForCompletion);
837    }
838
839    /**
840     * Creates a new hardware layer. A hardware layer built by calling this
841     * method will be treated as a texture layer, instead of as a render target.
842     *
843     * @return A hardware layer
844     */
845    TextureLayer createTextureLayer() {
846        long layer = nCreateTextureLayer(mNativeProxy);
847        return TextureLayer.adoptTextureLayer(this, layer);
848    }
849
850
851    void buildLayer(RenderNode node) {
852        nBuildLayer(mNativeProxy, node.getNativeDisplayList());
853    }
854
855
856    boolean copyLayerInto(final TextureLayer layer, final Bitmap bitmap) {
857        return nCopyLayerInto(mNativeProxy,
858                layer.getDeferredLayerUpdater(), bitmap);
859    }
860
861    /**
862     * Indicates that the specified hardware layer needs to be updated
863     * as soon as possible.
864     *
865     * @param layer The hardware layer that needs an update
866     */
867    void pushLayerUpdate(TextureLayer layer) {
868        nPushLayerUpdate(mNativeProxy, layer.getDeferredLayerUpdater());
869    }
870
871    /**
872     * Tells the HardwareRenderer that the layer is destroyed. The renderer
873     * should remove the layer from any update queues.
874     */
875    void onLayerDestroyed(TextureLayer layer) {
876        nCancelLayerUpdate(mNativeProxy, layer.getDeferredLayerUpdater());
877    }
878
879    /**
880     * Blocks until all previously queued work has completed.
881     */
882    void fence() {
883        nFence(mNativeProxy);
884    }
885
886    /**
887     * Prevents any further drawing until draw() is called. This is a signal
888     * that the contents of the RenderNode tree are no longer safe to play back.
889     * In practice this usually means that there are Functor pointers in the
890     * display list that are no longer valid.
891     */
892    void stopDrawing() {
893        nStopDrawing(mNativeProxy);
894    }
895
896    /**
897     * Called by {@link ViewRootImpl} when a new performTraverals is scheduled.
898     */
899    public void notifyFramePending() {
900        nNotifyFramePending(mNativeProxy);
901    }
902
903
904    void registerAnimatingRenderNode(RenderNode animator) {
905        nRegisterAnimatingRenderNode(mRootNode.mNativeRenderNode, animator.mNativeRenderNode);
906    }
907
908    void registerVectorDrawableAnimator(
909        AnimatedVectorDrawable.VectorDrawableAnimatorRT animator) {
910        nRegisterVectorDrawableAnimator(mRootNode.mNativeRenderNode,
911                animator.getAnimatorNativePtr());
912    }
913
914    public void serializeDisplayListTree() {
915        nSerializeDisplayListTree(mNativeProxy);
916    }
917
918    public static int copySurfaceInto(Surface surface, Rect srcRect, Bitmap bitmap) {
919        if (srcRect == null) {
920            // Empty rect means entire surface
921            return nCopySurfaceInto(surface, 0, 0, 0, 0, bitmap);
922        } else {
923            return nCopySurfaceInto(surface, srcRect.left, srcRect.top,
924                    srcRect.right, srcRect.bottom, bitmap);
925        }
926    }
927
928    /**
929     * Creates a {@link android.graphics.Bitmap.Config#HARDWARE} bitmap from the given
930     * RenderNode. Note that the RenderNode should be created as a root node (so x/y of 0,0), and
931     * not the RenderNode from a View.
932     **/
933    public static Bitmap createHardwareBitmap(RenderNode node, int width, int height) {
934        return nCreateHardwareBitmap(node.getNativeDisplayList(), width, height);
935    }
936
937    /**
938     * Sets whether or not high contrast text rendering is enabled. The setting is global
939     * but only affects content rendered after the change is made.
940     */
941    public static void setHighContrastText(boolean highContrastText) {
942        nSetHighContrastText(highContrastText);
943    }
944
945    /**
946     * If set RenderThread will avoid doing any IPC using instead a fake vsync & DisplayInfo source
947     */
948    public static void setIsolatedProcess(boolean isIsolated) {
949        nSetIsolatedProcess(isIsolated);
950    }
951
952    /**
953     * If set extra graphics debugging abilities will be enabled such as dumping skp
954     */
955    public static void setDebuggingEnabled(boolean enable) {
956        nSetDebuggingEnabled(enable);
957    }
958
959    @Override
960    protected void finalize() throws Throwable {
961        try {
962            nDeleteProxy(mNativeProxy);
963            mNativeProxy = 0;
964        } finally {
965            super.finalize();
966        }
967    }
968
969    /**
970     * Basic synchronous renderer. Currently only used to render the Magnifier, so use with care.
971     * TODO: deduplicate against ThreadedRenderer.
972     *
973     * @hide
974     */
975    public static class SimpleRenderer {
976        private final RenderNode mRootNode;
977        private long mNativeProxy;
978        private final float mLightY, mLightZ;
979        private Surface mSurface;
980        private final FrameInfo mFrameInfo = new FrameInfo();
981
982        public SimpleRenderer(final Context context, final String name, final Surface surface) {
983            final TypedArray a = context.obtainStyledAttributes(null, R.styleable.Lighting, 0, 0);
984            mLightY = a.getDimension(R.styleable.Lighting_lightY, 0);
985            mLightZ = a.getDimension(R.styleable.Lighting_lightZ, 0);
986            final float lightRadius = a.getDimension(R.styleable.Lighting_lightRadius, 0);
987            final int ambientShadowAlpha =
988                    (int) (255 * a.getFloat(R.styleable.Lighting_ambientShadowAlpha, 0) + 0.5f);
989            final int spotShadowAlpha =
990                    (int) (255 * a.getFloat(R.styleable.Lighting_spotShadowAlpha, 0) + 0.5f);
991            a.recycle();
992
993            final long rootNodePtr = nCreateRootRenderNode();
994            mRootNode = RenderNode.adopt(rootNodePtr);
995            mRootNode.setClipToBounds(false);
996            mNativeProxy = nCreateProxy(true /* translucent */, rootNodePtr);
997            nSetName(mNativeProxy, name);
998
999            ProcessInitializer.sInstance.init(context, mNativeProxy);
1000            nLoadSystemProperties(mNativeProxy);
1001
1002            nSetup(mNativeProxy, lightRadius, ambientShadowAlpha, spotShadowAlpha);
1003
1004            mSurface = surface;
1005            nUpdateSurface(mNativeProxy, surface);
1006        }
1007
1008        /**
1009         * Set the light center.
1010         */
1011        public void setLightCenter(final Display display,
1012                final int windowLeft, final int windowTop) {
1013            // Adjust light position for window offsets.
1014            final Point displaySize = new Point();
1015            display.getRealSize(displaySize);
1016            final float lightX = displaySize.x / 2f - windowLeft;
1017            final float lightY = mLightY - windowTop;
1018
1019            nSetLightCenter(mNativeProxy, lightX, lightY, mLightZ);
1020        }
1021
1022        public RenderNode getRootNode() {
1023            return mRootNode;
1024        }
1025
1026        /**
1027         * Draw the surface.
1028         */
1029        public void draw(final FrameDrawingCallback callback) {
1030            final long vsync = AnimationUtils.currentAnimationTimeMillis() * 1000000L;
1031            mFrameInfo.setVsync(vsync, vsync);
1032            mFrameInfo.addFlags(1 << 2 /* VSYNC */);
1033            if (callback != null) {
1034                nSetFrameCallback(mNativeProxy, callback);
1035            }
1036            nSyncAndDrawFrame(mNativeProxy, mFrameInfo.mFrameInfo, mFrameInfo.mFrameInfo.length);
1037        }
1038
1039        /**
1040         * Destroy the renderer.
1041         */
1042        public void destroy() {
1043            mSurface = null;
1044            nDestroy(mNativeProxy, mRootNode.mNativeRenderNode);
1045        }
1046
1047        @Override
1048        protected void finalize() throws Throwable {
1049            try {
1050                nDeleteProxy(mNativeProxy);
1051                mNativeProxy = 0;
1052            } finally {
1053                super.finalize();
1054            }
1055        }
1056    }
1057
1058    /**
1059     * Interface used to receive callbacks when a frame is being drawn.
1060     */
1061    public interface FrameDrawingCallback {
1062        /**
1063         * Invoked during a frame drawing.
1064         *
1065         * @param frame The id of the frame being drawn.
1066         */
1067        void onFrameDraw(long frame);
1068    }
1069
1070    private static class ProcessInitializer {
1071        static ProcessInitializer sInstance = new ProcessInitializer();
1072
1073        private boolean mInitialized = false;
1074
1075        private Context mAppContext;
1076        private IGraphicsStats mGraphicsStatsService;
1077        private IGraphicsStatsCallback mGraphicsStatsCallback = new IGraphicsStatsCallback.Stub() {
1078            @Override
1079            public void onRotateGraphicsStatsBuffer() throws RemoteException {
1080                rotateBuffer();
1081            }
1082        };
1083
1084        private ProcessInitializer() {}
1085
1086        synchronized void init(Context context, long renderProxy) {
1087            if (mInitialized) return;
1088            mInitialized = true;
1089            mAppContext = context.getApplicationContext();
1090
1091            initSched(renderProxy);
1092
1093            if (mAppContext != null) {
1094                initGraphicsStats();
1095            }
1096        }
1097
1098        private void initSched(long renderProxy) {
1099            try {
1100                int tid = nGetRenderThreadTid(renderProxy);
1101                ActivityManager.getService().setRenderThread(tid);
1102            } catch (Throwable t) {
1103                Log.w(LOG_TAG, "Failed to set scheduler for RenderThread", t);
1104            }
1105        }
1106
1107        private void initGraphicsStats() {
1108            try {
1109                IBinder binder = ServiceManager.getService("graphicsstats");
1110                if (binder == null) return;
1111                mGraphicsStatsService = IGraphicsStats.Stub.asInterface(binder);
1112                requestBuffer();
1113            } catch (Throwable t) {
1114                Log.w(LOG_TAG, "Could not acquire gfx stats buffer", t);
1115            }
1116        }
1117
1118        private void rotateBuffer() {
1119            nRotateProcessStatsBuffer();
1120            requestBuffer();
1121        }
1122
1123        private void requestBuffer() {
1124            try {
1125                final String pkg = mAppContext.getApplicationInfo().packageName;
1126                ParcelFileDescriptor pfd = mGraphicsStatsService
1127                        .requestBufferForProcess(pkg, mGraphicsStatsCallback);
1128                nSetProcessStatsBuffer(pfd.getFd());
1129                pfd.close();
1130            } catch (Throwable t) {
1131                Log.w(LOG_TAG, "Could not acquire gfx stats buffer", t);
1132            }
1133        }
1134    }
1135
1136    void addFrameMetricsObserver(FrameMetricsObserver observer) {
1137        long nativeObserver = nAddFrameMetricsObserver(mNativeProxy, observer);
1138        observer.mNative = new VirtualRefBasePtr(nativeObserver);
1139    }
1140
1141    void removeFrameMetricsObserver(FrameMetricsObserver observer) {
1142        nRemoveFrameMetricsObserver(mNativeProxy, observer.mNative.get());
1143        observer.mNative = null;
1144    }
1145
1146    /** b/68769804: For low FPS experiments. */
1147    public static void setFPSDivisor(int divisor) {
1148        nHackySetRTAnimationsEnabled(divisor <= 1);
1149    }
1150
1151    /**
1152     * Changes the OpenGL context priority if IMG_context_priority extension is available. Must be
1153     * called before any OpenGL context is created.
1154     *
1155     * @param priority The priority to use. Must be one of EGL_CONTEXT_PRIORITY_* values.
1156     */
1157    public static void setContextPriority(int priority) {
1158        nSetContextPriority(priority);
1159    }
1160
1161    /** Not actually public - internal use only. This doc to make lint happy */
1162    public static native void disableVsync();
1163
1164    static native void setupShadersDiskCache(String cacheFile, String skiaCacheFile);
1165
1166    private static native void nRotateProcessStatsBuffer();
1167    private static native void nSetProcessStatsBuffer(int fd);
1168    private static native int nGetRenderThreadTid(long nativeProxy);
1169
1170    private static native long nCreateRootRenderNode();
1171    private static native long nCreateProxy(boolean translucent, long rootRenderNode);
1172    private static native void nDeleteProxy(long nativeProxy);
1173
1174    private static native boolean nLoadSystemProperties(long nativeProxy);
1175    private static native void nSetName(long nativeProxy, String name);
1176
1177    private static native void nInitialize(long nativeProxy, Surface window);
1178    private static native void nUpdateSurface(long nativeProxy, Surface window);
1179    private static native boolean nPauseSurface(long nativeProxy, Surface window);
1180    private static native void nSetStopped(long nativeProxy, boolean stopped);
1181    private static native void nSetup(long nativeProxy,
1182            float lightRadius, int ambientShadowAlpha, int spotShadowAlpha);
1183    private static native void nSetLightCenter(long nativeProxy,
1184            float lightX, float lightY, float lightZ);
1185    private static native void nSetOpaque(long nativeProxy, boolean opaque);
1186    private static native void nSetWideGamut(long nativeProxy, boolean wideGamut);
1187    private static native int nSyncAndDrawFrame(long nativeProxy, long[] frameInfo, int size);
1188    private static native void nDestroy(long nativeProxy, long rootRenderNode);
1189    private static native void nRegisterAnimatingRenderNode(long rootRenderNode, long animatingNode);
1190    private static native void nRegisterVectorDrawableAnimator(long rootRenderNode, long animator);
1191
1192    private static native void nInvokeFunctor(long functor, boolean waitForCompletion);
1193
1194    private static native long nCreateTextureLayer(long nativeProxy);
1195    private static native void nBuildLayer(long nativeProxy, long node);
1196    private static native boolean nCopyLayerInto(long nativeProxy, long layer, Bitmap bitmap);
1197    private static native void nPushLayerUpdate(long nativeProxy, long layer);
1198    private static native void nCancelLayerUpdate(long nativeProxy, long layer);
1199    private static native void nDetachSurfaceTexture(long nativeProxy, long layer);
1200
1201    private static native void nDestroyHardwareResources(long nativeProxy);
1202    private static native void nTrimMemory(int level);
1203    private static native void nOverrideProperty(String name, String value);
1204
1205    private static native void nFence(long nativeProxy);
1206    private static native void nStopDrawing(long nativeProxy);
1207    private static native void nNotifyFramePending(long nativeProxy);
1208
1209    private static native void nSerializeDisplayListTree(long nativeProxy);
1210
1211    private static native void nDumpProfileInfo(long nativeProxy, FileDescriptor fd,
1212            @DumpFlags int dumpFlags);
1213
1214    private static native void nAddRenderNode(long nativeProxy, long rootRenderNode,
1215             boolean placeFront);
1216    private static native void nRemoveRenderNode(long nativeProxy, long rootRenderNode);
1217    private static native void nDrawRenderNode(long nativeProxy, long rootRenderNode);
1218    private static native void nSetContentDrawBounds(long nativeProxy, int left,
1219             int top, int right, int bottom);
1220    private static native void nSetFrameCallback(long nativeProxy, FrameDrawingCallback callback);
1221
1222    private static native long nAddFrameMetricsObserver(long nativeProxy, FrameMetricsObserver observer);
1223    private static native void nRemoveFrameMetricsObserver(long nativeProxy, long nativeObserver);
1224
1225    private static native int nCopySurfaceInto(Surface surface,
1226            int srcLeft, int srcTop, int srcRight, int srcBottom, Bitmap bitmap);
1227
1228    private static native Bitmap nCreateHardwareBitmap(long renderNode, int width, int height);
1229    private static native void nSetHighContrastText(boolean enabled);
1230    // For temporary experimentation b/66945974
1231    private static native void nHackySetRTAnimationsEnabled(boolean enabled);
1232    private static native void nSetDebuggingEnabled(boolean enabled);
1233    private static native void nSetIsolatedProcess(boolean enabled);
1234    private static native void nSetContextPriority(int priority);
1235}
1236