ThreadedRenderer.java revision 825fa4d5ae7b2907ee1769d09e6333306de2a92e
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.content.Context;
22import android.content.res.TypedArray;
23import android.graphics.Bitmap;
24import android.graphics.Point;
25import android.graphics.Rect;
26import android.os.Binder;
27import android.os.Handler;
28import android.os.IBinder;
29import android.os.Message;
30import android.os.ParcelFileDescriptor;
31import android.os.RemoteException;
32import android.os.ServiceManager;
33import android.os.Trace;
34import android.util.Log;
35import android.view.Surface.OutOfResourcesException;
36import android.view.View.AttachInfo;
37
38import com.android.internal.R;
39import com.android.internal.util.VirtualRefBasePtr;
40
41import java.io.File;
42import java.io.FileDescriptor;
43import java.io.PrintWriter;
44import java.lang.annotation.Retention;
45import java.lang.annotation.RetentionPolicy;
46import java.util.HashSet;
47
48/**
49 * Hardware 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
75    /**
76     * System property used to enable or disable dirty regions invalidation.
77     * This property is only queried if {@link #RENDER_DIRTY_REGIONS} is true.
78     * The default value of this property is assumed to be true.
79     *
80     * Possible values:
81     * "true", to enable partial invalidates
82     * "false", to disable partial invalidates
83     */
84    static final String RENDER_DIRTY_REGIONS_PROPERTY = "debug.hwui.render_dirty_regions";
85
86    /**
87     * System property used to enable or disable hardware rendering profiling.
88     * The default value of this property is assumed to be false.
89     *
90     * When profiling is enabled, the adb shell dumpsys gfxinfo command will
91     * output extra information about the time taken to execute by the last
92     * frames.
93     *
94     * Possible values:
95     * "true", to enable profiling
96     * "visual_bars", to enable profiling and visualize the results on screen
97     * "false", to disable profiling
98     *
99     * @see #PROFILE_PROPERTY_VISUALIZE_BARS
100     *
101     * @hide
102     */
103    public static final String PROFILE_PROPERTY = "debug.hwui.profile";
104
105    /**
106     * Value for {@link #PROFILE_PROPERTY}. When the property is set to this
107     * value, profiling data will be visualized on screen as a bar chart.
108     *
109     * @hide
110     */
111    public static final String PROFILE_PROPERTY_VISUALIZE_BARS = "visual_bars";
112
113    /**
114     * System property used to specify the number of frames to be used
115     * when doing hardware rendering profiling.
116     * The default value of this property is #PROFILE_MAX_FRAMES.
117     *
118     * When profiling is enabled, the adb shell dumpsys gfxinfo command will
119     * output extra information about the time taken to execute by the last
120     * frames.
121     *
122     * Possible values:
123     * "60", to set the limit of frames to 60
124     */
125    static final String PROFILE_MAXFRAMES_PROPERTY = "debug.hwui.profile.maxframes";
126
127    /**
128     * System property used to debug EGL configuration choice.
129     *
130     * Possible values:
131     * "choice", print the chosen configuration only
132     * "all", print all possible configurations
133     */
134    static final String PRINT_CONFIG_PROPERTY = "debug.hwui.print_config";
135
136    /**
137     * Turn on to draw dirty regions every other frame.
138     *
139     * Possible values:
140     * "true", to enable dirty regions debugging
141     * "false", to disable dirty regions debugging
142     *
143     * @hide
144     */
145    public static final String DEBUG_DIRTY_REGIONS_PROPERTY = "debug.hwui.show_dirty_regions";
146
147    /**
148     * Turn on to flash hardware layers when they update.
149     *
150     * Possible values:
151     * "true", to enable hardware layers updates debugging
152     * "false", to disable hardware layers updates debugging
153     *
154     * @hide
155     */
156    public static final String DEBUG_SHOW_LAYERS_UPDATES_PROPERTY =
157            "debug.hwui.show_layers_updates";
158
159    /**
160     * Controls overdraw debugging.
161     *
162     * Possible values:
163     * "false", to disable overdraw debugging
164     * "show", to show overdraw areas on screen
165     * "count", to display an overdraw counter
166     *
167     * @hide
168     */
169    public static final String DEBUG_OVERDRAW_PROPERTY = "debug.hwui.overdraw";
170
171    /**
172     * Value for {@link #DEBUG_OVERDRAW_PROPERTY}. When the property is set to this
173     * value, overdraw will be shown on screen by coloring pixels.
174     *
175     * @hide
176     */
177    public static final String OVERDRAW_PROPERTY_SHOW = "show";
178
179    /**
180     * Turn on to debug non-rectangular clip operations.
181     *
182     * Possible values:
183     * "hide", to disable this debug mode
184     * "highlight", highlight drawing commands tested against a non-rectangular clip
185     * "stencil", renders the clip region on screen when set
186     *
187     * @hide
188     */
189    public static final String DEBUG_SHOW_NON_RECTANGULAR_CLIP_PROPERTY =
190            "debug.hwui.show_non_rect_clip";
191
192    /**
193     * A process can set this flag to false to prevent the use of hardware
194     * rendering.
195     *
196     * @hide
197     */
198    public static boolean sRendererDisabled = false;
199
200    /**
201     * Further hardware renderer disabling for the system process.
202     *
203     * @hide
204     */
205    public static boolean sSystemRendererDisabled = false;
206
207    /**
208     * Invoke this method to disable hardware rendering in the current process.
209     *
210     * @hide
211     */
212    public static void disable(boolean system) {
213        sRendererDisabled = true;
214        if (system) {
215            sSystemRendererDisabled = true;
216        }
217    }
218
219    public static boolean sTrimForeground = false;
220
221    /**
222     * Controls whether or not the hardware renderer should aggressively
223     * trim memory. Note that this must not be set for any process that
224     * uses WebView! This should be only used by system_process or similar
225     * that do not go into the background.
226     */
227    public static void enableForegroundTrimming() {
228        sTrimForeground = true;
229    }
230
231    /**
232     * Indicates whether hardware acceleration is available under any form for
233     * the view hierarchy.
234     *
235     * @return True if the view hierarchy can potentially be hardware accelerated,
236     *         false otherwise
237     */
238    public static boolean isAvailable() {
239        return DisplayListCanvas.isAvailable();
240    }
241
242    /**
243     * Sets the directory to use as a persistent storage for hardware rendering
244     * resources.
245     *
246     * @param cacheDir A directory the current process can write to
247     *
248     * @hide
249     */
250    public static void setupDiskCache(File cacheDir) {
251        ThreadedRenderer.setupShadersDiskCache(new File(cacheDir, CACHE_PATH_SHADERS).getAbsolutePath());
252    }
253
254    /**
255     * Sets the library directory to use as a search path for vulkan layers.
256     *
257     * @param libDir A directory that contains vulkan layers
258     *
259     * @hide
260     */
261    public static void setLibDir(String libDir) {
262        ThreadedRenderer.setupVulkanLayerPath(libDir);
263    }
264
265    /**
266     * Creates a hardware renderer using OpenGL.
267     *
268     * @param translucent True if the surface is translucent, false otherwise
269     *
270     * @return A hardware renderer backed by OpenGL.
271     */
272    public static ThreadedRenderer create(Context context, boolean translucent) {
273        ThreadedRenderer renderer = null;
274        if (DisplayListCanvas.isAvailable()) {
275            renderer = new ThreadedRenderer(context, translucent);
276        }
277        return renderer;
278    }
279
280    /**
281     * Invoke this method when the system is running out of memory. This
282     * method will attempt to recover as much memory as possible, based on
283     * the specified hint.
284     *
285     * @param level Hint about the amount of memory that should be trimmed,
286     *              see {@link android.content.ComponentCallbacks}
287     */
288    public static void trimMemory(int level) {
289        nTrimMemory(level);
290    }
291
292    public static void overrideProperty(@NonNull String name, @NonNull String value) {
293        if (name == null || value == null) {
294            throw new IllegalArgumentException("name and value must be non-null");
295        }
296        nOverrideProperty(name, value);
297    }
298
299    public static void dumpProfileData(byte[] data, FileDescriptor fd) {
300        nDumpProfileData(data, fd);
301    }
302
303    // Keep in sync with DrawFrameTask.h SYNC_* flags
304    // Nothing interesting to report
305    private static final int SYNC_OK = 0;
306    // Needs a ViewRoot invalidate
307    private static final int SYNC_INVALIDATE_REQUIRED = 1 << 0;
308    // Spoiler: the reward is GPU-accelerated drawing, better find that Surface!
309    private static final int SYNC_LOST_SURFACE_REWARD_IF_FOUND = 1 << 1;
310
311    private static final String[] VISUALIZERS = {
312        PROFILE_PROPERTY_VISUALIZE_BARS,
313    };
314
315    private static final int FLAG_DUMP_FRAMESTATS   = 1 << 0;
316    private static final int FLAG_DUMP_RESET        = 1 << 1;
317
318    @IntDef(flag = true, value = {
319            FLAG_DUMP_FRAMESTATS, FLAG_DUMP_RESET })
320    @Retention(RetentionPolicy.SOURCE)
321    public @interface DumpFlags {}
322
323    // Size of the rendered content.
324    private int mWidth, mHeight;
325
326    // Actual size of the drawing surface.
327    private int mSurfaceWidth, mSurfaceHeight;
328
329    // Insets between the drawing surface and rendered content. These are
330    // applied as translation when updating the root render node.
331    private int mInsetTop, mInsetLeft;
332
333    // Whether the surface has insets. Used to protect opacity.
334    private boolean mHasInsets;
335
336    // Light and shadow properties specified by the theme.
337    private final float mLightY;
338    private final float mLightZ;
339    private final float mLightRadius;
340    private final int mAmbientShadowAlpha;
341    private final int mSpotShadowAlpha;
342
343    private long mNativeProxy;
344    private boolean mInitialized = false;
345    private RenderNode mRootNode;
346    private Choreographer mChoreographer;
347    private boolean mRootNodeNeedsUpdate;
348
349    // In case of multi threaded render nodes, these bounds indicate the content bounds against
350    // which the backdrop needs to be cropped against.
351    private final Rect mCurrentContentBounds = new Rect();
352    private final Rect mStagedContentBounds = new Rect();
353
354    private boolean mEnabled;
355    private boolean mRequested = true;
356
357    ThreadedRenderer(Context context, boolean translucent) {
358        final TypedArray a = context.obtainStyledAttributes(null, R.styleable.Lighting, 0, 0);
359        mLightY = a.getDimension(R.styleable.Lighting_lightY, 0);
360        mLightZ = a.getDimension(R.styleable.Lighting_lightZ, 0);
361        mLightRadius = a.getDimension(R.styleable.Lighting_lightRadius, 0);
362        mAmbientShadowAlpha =
363                (int) (255 * a.getFloat(R.styleable.Lighting_ambientShadowAlpha, 0) + 0.5f);
364        mSpotShadowAlpha = (int) (255 * a.getFloat(R.styleable.Lighting_spotShadowAlpha, 0) + 0.5f);
365        a.recycle();
366
367        long rootNodePtr = nCreateRootRenderNode();
368        mRootNode = RenderNode.adopt(rootNodePtr);
369        mRootNode.setClipToBounds(false);
370        mNativeProxy = nCreateProxy(translucent, rootNodePtr);
371
372        ProcessInitializer.sInstance.init(context, mNativeProxy);
373
374        loadSystemProperties();
375    }
376
377    /**
378     * Destroys the hardware rendering context.
379     */
380    void destroy() {
381        mInitialized = false;
382        updateEnabledState(null);
383        nDestroy(mNativeProxy, mRootNode.mNativeRenderNode);
384    }
385
386    /**
387     * Indicates whether hardware acceleration is currently enabled.
388     *
389     * @return True if hardware acceleration is in use, false otherwise.
390     */
391    boolean isEnabled() {
392        return mEnabled;
393    }
394
395    /**
396     * Indicates whether hardware acceleration is currently enabled.
397     *
398     * @param enabled True if the hardware renderer is in use, false otherwise.
399     */
400    void setEnabled(boolean enabled) {
401        mEnabled = enabled;
402    }
403
404    /**
405     * Indicates whether hardware acceleration is currently request but not
406     * necessarily enabled yet.
407     *
408     * @return True if requested, false otherwise.
409     */
410    boolean isRequested() {
411        return mRequested;
412    }
413
414    /**
415     * Indicates whether hardware acceleration is currently requested but not
416     * necessarily enabled yet.
417     *
418     * @return True to request hardware acceleration, false otherwise.
419     */
420    void setRequested(boolean requested) {
421        mRequested = requested;
422    }
423
424    private void updateEnabledState(Surface surface) {
425        if (surface == null || !surface.isValid()) {
426            setEnabled(false);
427        } else {
428            setEnabled(mInitialized);
429        }
430    }
431
432    /**
433     * Initializes the hardware renderer for the specified surface.
434     *
435     * @param surface The surface to hardware accelerate
436     *
437     * @return True if the initialization was successful, false otherwise.
438     */
439    boolean initialize(Surface surface) throws OutOfResourcesException {
440        boolean status = !mInitialized;
441        mInitialized = true;
442        updateEnabledState(surface);
443        nInitialize(mNativeProxy, surface);
444        return status;
445    }
446
447    /**
448     * Initializes the hardware renderer for the specified surface and setup the
449     * renderer for drawing, if needed. This is invoked when the ViewAncestor has
450     * potentially lost the hardware renderer. The hardware renderer should be
451     * reinitialized and setup when the render {@link #isRequested()} and
452     * {@link #isEnabled()}.
453     *
454     * @param width The width of the drawing surface.
455     * @param height The height of the drawing surface.
456     * @param attachInfo Information about the window.
457     * @param surface The surface to hardware accelerate
458     * @param surfaceInsets The drawing surface insets to apply
459     *
460     * @return true if the surface was initialized, false otherwise. Returning
461     *         false might mean that the surface was already initialized.
462     */
463    boolean initializeIfNeeded(int width, int height, View.AttachInfo attachInfo,
464            Surface surface, Rect surfaceInsets) throws OutOfResourcesException {
465        if (isRequested()) {
466            // We lost the gl context, so recreate it.
467            if (!isEnabled()) {
468                if (initialize(surface)) {
469                    setup(width, height, attachInfo, surfaceInsets);
470                    return true;
471                }
472            }
473        }
474        return false;
475    }
476
477    /**
478     * Updates the hardware renderer for the specified surface.
479     *
480     * @param surface The surface to hardware accelerate
481     */
482    void updateSurface(Surface surface) throws OutOfResourcesException {
483        updateEnabledState(surface);
484        nUpdateSurface(mNativeProxy, surface);
485    }
486
487    /**
488     * Stops any rendering into the surface. Use this if it is unclear whether
489     * or not the surface used by the HardwareRenderer will be changing. It
490     * Suspends any rendering into the surface, but will not do any destruction
491     */
492    boolean pauseSurface(Surface surface) {
493        return nPauseSurface(mNativeProxy, surface);
494    }
495
496    /**
497     * Destroys all hardware rendering resources associated with the specified
498     * view hierarchy.
499     *
500     * @param view The root of the view hierarchy
501     */
502    void destroyHardwareResources(View view) {
503        destroyResources(view);
504        nDestroyHardwareResources(mNativeProxy);
505    }
506
507    private static void destroyResources(View view) {
508        view.destroyHardwareResources();
509
510        if (view instanceof ViewGroup) {
511            ViewGroup group = (ViewGroup) view;
512
513            int count = group.getChildCount();
514            for (int i = 0; i < count; i++) {
515                destroyResources(group.getChildAt(i));
516            }
517        }
518    }
519
520    /**
521     * This method should be invoked whenever the current hardware renderer
522     * context should be reset.
523     *
524     * @param surface The surface to hardware accelerate
525     */
526    void invalidate(Surface surface) {
527        updateSurface(surface);
528    }
529
530    /**
531     * Detaches the layer's surface texture from the GL context and releases
532     * the texture id
533     */
534    void detachSurfaceTexture(long hardwareLayer) {
535        nDetachSurfaceTexture(mNativeProxy, hardwareLayer);
536    }
537
538    /**
539     * Sets up the renderer for drawing.
540     *
541     * @param width The width of the drawing surface.
542     * @param height The height of the drawing surface.
543     * @param attachInfo Information about the window.
544     * @param surfaceInsets The drawing surface insets to apply
545     */
546    void setup(int width, int height, AttachInfo attachInfo, Rect surfaceInsets) {
547        mWidth = width;
548        mHeight = height;
549
550        if (surfaceInsets != null && (surfaceInsets.left != 0 || surfaceInsets.right != 0
551                || surfaceInsets.top != 0 || surfaceInsets.bottom != 0)) {
552            mHasInsets = true;
553            mInsetLeft = surfaceInsets.left;
554            mInsetTop = surfaceInsets.top;
555            mSurfaceWidth = width + mInsetLeft + surfaceInsets.right;
556            mSurfaceHeight = height + mInsetTop + surfaceInsets.bottom;
557
558            // If the surface has insets, it can't be opaque.
559            setOpaque(false);
560        } else {
561            mHasInsets = false;
562            mInsetLeft = 0;
563            mInsetTop = 0;
564            mSurfaceWidth = width;
565            mSurfaceHeight = height;
566        }
567
568        mRootNode.setLeftTopRightBottom(-mInsetLeft, -mInsetTop, mSurfaceWidth, mSurfaceHeight);
569        nSetup(mNativeProxy, mSurfaceWidth, mSurfaceHeight, mLightRadius,
570                mAmbientShadowAlpha, mSpotShadowAlpha);
571
572        setLightCenter(attachInfo);
573    }
574
575    /**
576     * Updates the light position based on the position of the window.
577     *
578     * @param attachInfo Information about the window.
579     */
580    void setLightCenter(AttachInfo attachInfo) {
581        // Adjust light position for window offsets.
582        final Point displaySize = attachInfo.mPoint;
583        attachInfo.mDisplay.getRealSize(displaySize);
584        final float lightX = displaySize.x / 2f - attachInfo.mWindowLeft;
585        final float lightY = mLightY - attachInfo.mWindowTop;
586
587        nSetLightCenter(mNativeProxy, lightX, lightY, mLightZ);
588    }
589
590    /**
591     * Change the HardwareRenderer's opacity
592     */
593    void setOpaque(boolean opaque) {
594        nSetOpaque(mNativeProxy, opaque && !mHasInsets);
595    }
596
597    /**
598     * Gets the current width of the surface. This is the width that the surface
599     * was last set to in a call to {@link #setup(int, int, View.AttachInfo, Rect)}.
600     *
601     * @return the current width of the surface
602     */
603    int getWidth() {
604        return mWidth;
605    }
606
607    /**
608     * Gets the current height of the surface. This is the height that the surface
609     * was last set to in a call to {@link #setup(int, int, View.AttachInfo, Rect)}.
610     *
611     * @return the current width of the surface
612     */
613    int getHeight() {
614        return mHeight;
615    }
616
617    /**
618     * Outputs extra debugging information in the specified file descriptor.
619     */
620    void dumpGfxInfo(PrintWriter pw, FileDescriptor fd, String[] args) {
621        pw.flush();
622        int flags = 0;
623        for (int i = 0; i < args.length; i++) {
624            switch (args[i]) {
625                case "framestats":
626                    flags |= FLAG_DUMP_FRAMESTATS;
627                    break;
628                case "reset":
629                    flags |= FLAG_DUMP_RESET;
630                    break;
631            }
632        }
633        nDumpProfileInfo(mNativeProxy, fd, flags);
634    }
635
636    /**
637     * Loads system properties used by the renderer. This method is invoked
638     * whenever system properties are modified. Implementations can use this
639     * to trigger live updates of the renderer based on properties.
640     *
641     * @return True if a property has changed.
642     */
643    boolean loadSystemProperties() {
644        boolean changed = nLoadSystemProperties(mNativeProxy);
645        if (changed) {
646            invalidateRoot();
647        }
648        return changed;
649    }
650
651    private void updateViewTreeDisplayList(View view) {
652        view.mPrivateFlags |= View.PFLAG_DRAWN;
653        view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
654                == View.PFLAG_INVALIDATED;
655        view.mPrivateFlags &= ~View.PFLAG_INVALIDATED;
656        view.updateDisplayListIfDirty();
657        view.mRecreateDisplayList = false;
658    }
659
660    private void updateRootDisplayList(View view, HardwareDrawCallbacks callbacks) {
661        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Record View#draw()");
662        updateViewTreeDisplayList(view);
663
664        if (mRootNodeNeedsUpdate || !mRootNode.isValid()) {
665            DisplayListCanvas canvas = mRootNode.start(mSurfaceWidth, mSurfaceHeight);
666            try {
667                final int saveCount = canvas.save();
668                canvas.translate(mInsetLeft, mInsetTop);
669                callbacks.onHardwarePreDraw(canvas);
670
671                canvas.insertReorderBarrier();
672                canvas.drawRenderNode(view.updateDisplayListIfDirty());
673                canvas.insertInorderBarrier();
674
675                callbacks.onHardwarePostDraw(canvas);
676                canvas.restoreToCount(saveCount);
677                mRootNodeNeedsUpdate = false;
678            } finally {
679                mRootNode.end(canvas);
680            }
681        }
682        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
683    }
684
685    /**
686     * Adds a rendernode to the renderer which can be drawn and changed asynchronously to the
687     * rendernode of the UI thread.
688     * @param node The node to add.
689     * @param placeFront If true, the render node will be placed in front of the content node,
690     *                   otherwise behind the content node.
691     */
692    public void addRenderNode(RenderNode node, boolean placeFront) {
693        nAddRenderNode(mNativeProxy, node.mNativeRenderNode, placeFront);
694    }
695
696    /**
697     * Only especially added render nodes can be removed.
698     * @param node The node which was added via addRenderNode which should get removed again.
699     */
700    public void removeRenderNode(RenderNode node) {
701        nRemoveRenderNode(mNativeProxy, node.mNativeRenderNode);
702    }
703
704    /**
705     * Draws a particular render node. If the node is not the content node, only the additional
706     * nodes will get drawn and the content remains untouched.
707     * @param node The node to be drawn.
708     */
709    public void drawRenderNode(RenderNode node) {
710        nDrawRenderNode(mNativeProxy, node.mNativeRenderNode);
711    }
712
713    /**
714     * To avoid unnecessary overdrawing of the main content all additionally passed render nodes
715     * will be prevented to overdraw this area. It will be synchronized with the draw call.
716     * This should be updated in the content view's draw call.
717     * @param left The left side of the protected bounds.
718     * @param top The top side of the protected bounds.
719     * @param right The right side of the protected bounds.
720     * @param bottom The bottom side of the protected bounds.
721     */
722    public void setContentDrawBounds(int left, int top, int right, int bottom) {
723        mStagedContentBounds.set(left, top, right, bottom);
724    }
725
726    /**
727     * Interface used to receive callbacks whenever a view is drawn by
728     * a hardware renderer instance.
729     */
730    interface HardwareDrawCallbacks {
731        /**
732         * Invoked before a view is drawn by a hardware renderer.
733         * This method can be used to apply transformations to the
734         * canvas but no drawing command should be issued.
735         *
736         * @param canvas The Canvas used to render the view.
737         */
738        void onHardwarePreDraw(DisplayListCanvas canvas);
739
740        /**
741         * Invoked after a view is drawn by a hardware renderer.
742         * It is safe to invoke drawing commands from this method.
743         *
744         * @param canvas The Canvas used to render the view.
745         */
746        void onHardwarePostDraw(DisplayListCanvas canvas);
747    }
748
749    /**
750     *  Indicates that the content drawn by HardwareDrawCallbacks needs to
751     *  be updated, which will be done by the next call to draw()
752     */
753    void invalidateRoot() {
754        mRootNodeNeedsUpdate = true;
755    }
756
757    /**
758     * Draws the specified view.
759     *
760     * @param view The view to draw.
761     * @param attachInfo AttachInfo tied to the specified view.
762     * @param callbacks Callbacks invoked when drawing happens.
763     */
764    void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks) {
765        attachInfo.mIgnoreDirtyState = true;
766
767        final Choreographer choreographer = attachInfo.mViewRootImpl.mChoreographer;
768        choreographer.mFrameInfo.markDrawStart();
769
770        updateRootDisplayList(view, callbacks);
771        // The main content view was updating the content bounds and we transfer them to the
772        // renderer.
773        if (!mCurrentContentBounds.equals(mStagedContentBounds)) {
774            mCurrentContentBounds.set(mStagedContentBounds);
775            nSetContentDrawBounds(mNativeProxy, mCurrentContentBounds.left,
776                    mCurrentContentBounds.top, mCurrentContentBounds.right,
777                    mCurrentContentBounds.bottom);
778        }
779
780        attachInfo.mIgnoreDirtyState = false;
781
782        // register animating rendernodes which started animating prior to renderer
783        // creation, which is typical for animators started prior to first draw
784        if (attachInfo.mPendingAnimatingRenderNodes != null) {
785            final int count = attachInfo.mPendingAnimatingRenderNodes.size();
786            for (int i = 0; i < count; i++) {
787                registerAnimatingRenderNode(
788                        attachInfo.mPendingAnimatingRenderNodes.get(i));
789            }
790            attachInfo.mPendingAnimatingRenderNodes.clear();
791            // We don't need this anymore as subsequent calls to
792            // ViewRootImpl#attachRenderNodeAnimator will go directly to us.
793            attachInfo.mPendingAnimatingRenderNodes = null;
794        }
795
796        final long[] frameInfo = choreographer.mFrameInfo.mFrameInfo;
797        int syncResult = nSyncAndDrawFrame(mNativeProxy, frameInfo, frameInfo.length);
798        if ((syncResult & SYNC_LOST_SURFACE_REWARD_IF_FOUND) != 0) {
799            setEnabled(false);
800            attachInfo.mViewRootImpl.mSurface.release();
801            // Invalidate since we failed to draw. This should fetch a Surface
802            // if it is still needed or do nothing if we are no longer drawing
803            attachInfo.mViewRootImpl.invalidate();
804        }
805        if ((syncResult & SYNC_INVALIDATE_REQUIRED) != 0) {
806            attachInfo.mViewRootImpl.invalidate();
807        }
808    }
809
810    static void invokeFunctor(long functor, boolean waitForCompletion) {
811        nInvokeFunctor(functor, waitForCompletion);
812    }
813
814    /**
815     * Creates a new hardware layer. A hardware layer built by calling this
816     * method will be treated as a texture layer, instead of as a render target.
817     *
818     * @return A hardware layer
819     */
820    HardwareLayer createTextureLayer() {
821        long layer = nCreateTextureLayer(mNativeProxy);
822        return HardwareLayer.adoptTextureLayer(this, layer);
823    }
824
825
826    void buildLayer(RenderNode node) {
827        nBuildLayer(mNativeProxy, node.getNativeDisplayList());
828    }
829
830
831    boolean copyLayerInto(final HardwareLayer layer, final Bitmap bitmap) {
832        return nCopyLayerInto(mNativeProxy,
833                layer.getDeferredLayerUpdater(), bitmap);
834    }
835
836    /**
837     * Indicates that the specified hardware layer needs to be updated
838     * as soon as possible.
839     *
840     * @param layer The hardware layer that needs an update
841     */
842    void pushLayerUpdate(HardwareLayer layer) {
843        nPushLayerUpdate(mNativeProxy, layer.getDeferredLayerUpdater());
844    }
845
846    /**
847     * Tells the HardwareRenderer that the layer is destroyed. The renderer
848     * should remove the layer from any update queues.
849     */
850    void onLayerDestroyed(HardwareLayer layer) {
851        nCancelLayerUpdate(mNativeProxy, layer.getDeferredLayerUpdater());
852    }
853
854    /**
855     * Optional, sets the name of the renderer. Useful for debugging purposes.
856     *
857     * @param name The name of this renderer, can be null
858     */
859    void setName(String name) {
860        nSetName(mNativeProxy, name);
861    }
862
863    /**
864     * Blocks until all previously queued work has completed.
865     */
866    void fence() {
867        nFence(mNativeProxy);
868    }
869
870    /**
871     * Prevents any further drawing until draw() is called. This is a signal
872     * that the contents of the RenderNode tree are no longer safe to play back.
873     * In practice this usually means that there are Functor pointers in the
874     * display list that are no longer valid.
875     */
876    void stopDrawing() {
877        nStopDrawing(mNativeProxy);
878    }
879
880    /**
881     * Called by {@link ViewRootImpl} when a new performTraverals is scheduled.
882     */
883    public void notifyFramePending() {
884        nNotifyFramePending(mNativeProxy);
885    }
886
887
888    void registerAnimatingRenderNode(RenderNode animator) {
889        nRegisterAnimatingRenderNode(mRootNode.mNativeRenderNode, animator.mNativeRenderNode);
890    }
891
892    public void serializeDisplayListTree() {
893        nSerializeDisplayListTree(mNativeProxy);
894    }
895
896    @Override
897    protected void finalize() throws Throwable {
898        try {
899            nDeleteProxy(mNativeProxy);
900            mNativeProxy = 0;
901        } finally {
902            super.finalize();
903        }
904    }
905
906    private static class ProcessInitializer {
907        static ProcessInitializer sInstance = new ProcessInitializer();
908        private static IBinder sProcToken;
909
910        private boolean mInitialized = false;
911
912        private ProcessInitializer() {}
913
914        synchronized void init(Context context, long renderProxy) {
915            if (mInitialized) return;
916            mInitialized = true;
917            initGraphicsStats(context, renderProxy);
918            initAssetAtlas(context, renderProxy);
919        }
920
921        private static void initGraphicsStats(Context context, long renderProxy) {
922            try {
923                IBinder binder = ServiceManager.getService("graphicsstats");
924                if (binder == null) return;
925                IGraphicsStats graphicsStatsService = IGraphicsStats.Stub
926                        .asInterface(binder);
927                sProcToken = new Binder();
928                final String pkg = context.getApplicationInfo().packageName;
929                ParcelFileDescriptor pfd = graphicsStatsService.
930                        requestBufferForProcess(pkg, sProcToken);
931                nSetProcessStatsBuffer(renderProxy, pfd.getFd());
932                pfd.close();
933            } catch (Throwable t) {
934                Log.w(LOG_TAG, "Could not acquire gfx stats buffer", t);
935            }
936        }
937
938        private static void initAssetAtlas(Context context, long renderProxy) {
939            IBinder binder = ServiceManager.getService("assetatlas");
940            if (binder == null) return;
941
942            IAssetAtlas atlas = IAssetAtlas.Stub.asInterface(binder);
943            try {
944                if (atlas.isCompatible(android.os.Process.myPpid())) {
945                    GraphicBuffer buffer = atlas.getBuffer();
946                    if (buffer != null) {
947                        long[] map = atlas.getMap();
948                        if (map != null) {
949                            nSetAtlas(renderProxy, buffer, map);
950                        }
951                        // If IAssetAtlas is not the same class as the IBinder
952                        // we are using a remote service and we can safely
953                        // destroy the graphic buffer
954                        if (atlas.getClass() != binder.getClass()) {
955                            buffer.destroy();
956                        }
957                    }
958                }
959            } catch (RemoteException e) {
960                Log.w(LOG_TAG, "Could not acquire atlas", e);
961            }
962        }
963    }
964
965    void addFrameMetricsObserver(FrameMetricsObserver observer) {
966        long nativeObserver = nAddFrameMetricsObserver(mNativeProxy, observer);
967        observer.mNative = new VirtualRefBasePtr(nativeObserver);
968    }
969
970    void removeFrameMetricsObserver(FrameMetricsObserver observer) {
971        nRemoveFrameMetricsObserver(mNativeProxy, observer.mNative.get());
972        observer.mNative = null;
973    }
974
975    static native void setupShadersDiskCache(String cacheFile);
976    static native void setupVulkanLayerPath(String layerPath);
977
978    private static native void nSetAtlas(long nativeProxy, GraphicBuffer buffer, long[] map);
979    private static native void nSetProcessStatsBuffer(long nativeProxy, int fd);
980
981    private static native long nCreateRootRenderNode();
982    private static native long nCreateProxy(boolean translucent, long rootRenderNode);
983    private static native void nDeleteProxy(long nativeProxy);
984
985    private static native boolean nLoadSystemProperties(long nativeProxy);
986    private static native void nSetName(long nativeProxy, String name);
987
988    private static native void nInitialize(long nativeProxy, Surface window);
989    private static native void nUpdateSurface(long nativeProxy, Surface window);
990    private static native boolean nPauseSurface(long nativeProxy, Surface window);
991    private static native void nSetup(long nativeProxy, int width, int height,
992            float lightRadius, int ambientShadowAlpha, int spotShadowAlpha);
993    private static native void nSetLightCenter(long nativeProxy,
994            float lightX, float lightY, float lightZ);
995    private static native void nSetOpaque(long nativeProxy, boolean opaque);
996    private static native int nSyncAndDrawFrame(long nativeProxy, long[] frameInfo, int size);
997    private static native void nDestroy(long nativeProxy, long rootRenderNode);
998    private static native void nRegisterAnimatingRenderNode(long rootRenderNode, long animatingNode);
999
1000    private static native void nInvokeFunctor(long functor, boolean waitForCompletion);
1001
1002    private static native long nCreateTextureLayer(long nativeProxy);
1003    private static native void nBuildLayer(long nativeProxy, long node);
1004    private static native boolean nCopyLayerInto(long nativeProxy, long layer, Bitmap bitmap);
1005    private static native void nPushLayerUpdate(long nativeProxy, long layer);
1006    private static native void nCancelLayerUpdate(long nativeProxy, long layer);
1007    private static native void nDetachSurfaceTexture(long nativeProxy, long layer);
1008
1009    private static native void nDestroyHardwareResources(long nativeProxy);
1010    private static native void nTrimMemory(int level);
1011    private static native void nOverrideProperty(String name, String value);
1012
1013    private static native void nFence(long nativeProxy);
1014    private static native void nStopDrawing(long nativeProxy);
1015    private static native void nNotifyFramePending(long nativeProxy);
1016
1017    private static native void nSerializeDisplayListTree(long nativeProxy);
1018
1019    private static native void nDumpProfileInfo(long nativeProxy, FileDescriptor fd,
1020            @DumpFlags int dumpFlags);
1021    private static native void nDumpProfileData(byte[] data, FileDescriptor fd);
1022
1023    private static native void nAddRenderNode(long nativeProxy, long rootRenderNode,
1024             boolean placeFront);
1025    private static native void nRemoveRenderNode(long nativeProxy, long rootRenderNode);
1026    private static native void nDrawRenderNode(long nativeProxy, long rootRenderNode);
1027    private static native void nSetContentDrawBounds(long nativeProxy, int left,
1028             int top, int right, int bottom);
1029
1030    private static native long nAddFrameMetricsObserver(long nativeProxy, FrameMetricsObserver observer);
1031    private static native void nRemoveFrameMetricsObserver(long nativeProxy, long nativeObserver);
1032}
1033