ThreadedRenderer.java revision 9a17da8125c36c82ba73e7f4b3ed80b9c633767f
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    // setStopped is true, drawing is false
311    // TODO: Remove this and SYNC_LOST_SURFACE_REWARD_IF_FOUND?
312    // This flag isn't really used as there's nothing that we care to do
313    // in response, so it really just exists to differentiate from LOST_SURFACE
314    // but possibly both can just be deleted.
315    private static final int SYNC_CONTEXT_IS_STOPPED = 1 << 2;
316
317    private static final String[] VISUALIZERS = {
318        PROFILE_PROPERTY_VISUALIZE_BARS,
319    };
320
321    private static final int FLAG_DUMP_FRAMESTATS   = 1 << 0;
322    private static final int FLAG_DUMP_RESET        = 1 << 1;
323
324    @IntDef(flag = true, value = {
325            FLAG_DUMP_FRAMESTATS, FLAG_DUMP_RESET })
326    @Retention(RetentionPolicy.SOURCE)
327    public @interface DumpFlags {}
328
329    // Size of the rendered content.
330    private int mWidth, mHeight;
331
332    // Actual size of the drawing surface.
333    private int mSurfaceWidth, mSurfaceHeight;
334
335    // Insets between the drawing surface and rendered content. These are
336    // applied as translation when updating the root render node.
337    private int mInsetTop, mInsetLeft;
338
339    // Whether the surface has insets. Used to protect opacity.
340    private boolean mHasInsets;
341
342    // Light and shadow properties specified by the theme.
343    private final float mLightY;
344    private final float mLightZ;
345    private final float mLightRadius;
346    private final int mAmbientShadowAlpha;
347    private final int mSpotShadowAlpha;
348
349    private long mNativeProxy;
350    private boolean mInitialized = false;
351    private RenderNode mRootNode;
352    private Choreographer mChoreographer;
353    private boolean mRootNodeNeedsUpdate;
354
355    // In case of multi threaded render nodes, these bounds indicate the content bounds against
356    // which the backdrop needs to be cropped against.
357    private final Rect mCurrentContentBounds = new Rect();
358    private final Rect mStagedContentBounds = new Rect();
359
360    private boolean mEnabled;
361    private boolean mRequested = true;
362
363    ThreadedRenderer(Context context, boolean translucent) {
364        final TypedArray a = context.obtainStyledAttributes(null, R.styleable.Lighting, 0, 0);
365        mLightY = a.getDimension(R.styleable.Lighting_lightY, 0);
366        mLightZ = a.getDimension(R.styleable.Lighting_lightZ, 0);
367        mLightRadius = a.getDimension(R.styleable.Lighting_lightRadius, 0);
368        mAmbientShadowAlpha =
369                (int) (255 * a.getFloat(R.styleable.Lighting_ambientShadowAlpha, 0) + 0.5f);
370        mSpotShadowAlpha = (int) (255 * a.getFloat(R.styleable.Lighting_spotShadowAlpha, 0) + 0.5f);
371        a.recycle();
372
373        long rootNodePtr = nCreateRootRenderNode();
374        mRootNode = RenderNode.adopt(rootNodePtr);
375        mRootNode.setClipToBounds(false);
376        mNativeProxy = nCreateProxy(translucent, rootNodePtr);
377
378        ProcessInitializer.sInstance.init(context, mNativeProxy);
379
380        loadSystemProperties();
381    }
382
383    /**
384     * Destroys the hardware rendering context.
385     */
386    void destroy() {
387        mInitialized = false;
388        updateEnabledState(null);
389        nDestroy(mNativeProxy, mRootNode.mNativeRenderNode);
390    }
391
392    /**
393     * Indicates whether hardware acceleration is currently enabled.
394     *
395     * @return True if hardware acceleration is in use, false otherwise.
396     */
397    boolean isEnabled() {
398        return mEnabled;
399    }
400
401    /**
402     * Indicates whether hardware acceleration is currently enabled.
403     *
404     * @param enabled True if the hardware renderer is in use, false otherwise.
405     */
406    void setEnabled(boolean enabled) {
407        mEnabled = enabled;
408    }
409
410    /**
411     * Indicates whether hardware acceleration is currently request but not
412     * necessarily enabled yet.
413     *
414     * @return True if requested, false otherwise.
415     */
416    boolean isRequested() {
417        return mRequested;
418    }
419
420    /**
421     * Indicates whether hardware acceleration is currently requested but not
422     * necessarily enabled yet.
423     *
424     * @return True to request hardware acceleration, false otherwise.
425     */
426    void setRequested(boolean requested) {
427        mRequested = requested;
428    }
429
430    private void updateEnabledState(Surface surface) {
431        if (surface == null || !surface.isValid()) {
432            setEnabled(false);
433        } else {
434            setEnabled(mInitialized);
435        }
436    }
437
438    /**
439     * Initializes the hardware renderer for the specified surface.
440     *
441     * @param surface The surface to hardware accelerate
442     *
443     * @return True if the initialization was successful, false otherwise.
444     */
445    boolean initialize(Surface surface) throws OutOfResourcesException {
446        boolean status = !mInitialized;
447        mInitialized = true;
448        updateEnabledState(surface);
449        nInitialize(mNativeProxy, surface);
450        return status;
451    }
452
453    /**
454     * Initializes the hardware renderer for the specified surface and setup the
455     * renderer for drawing, if needed. This is invoked when the ViewAncestor has
456     * potentially lost the hardware renderer. The hardware renderer should be
457     * reinitialized and setup when the render {@link #isRequested()} and
458     * {@link #isEnabled()}.
459     *
460     * @param width The width of the drawing surface.
461     * @param height The height of the drawing surface.
462     * @param attachInfo Information about the window.
463     * @param surface The surface to hardware accelerate
464     * @param surfaceInsets The drawing surface insets to apply
465     *
466     * @return true if the surface was initialized, false otherwise. Returning
467     *         false might mean that the surface was already initialized.
468     */
469    boolean initializeIfNeeded(int width, int height, View.AttachInfo attachInfo,
470            Surface surface, Rect surfaceInsets) throws OutOfResourcesException {
471        if (isRequested()) {
472            // We lost the gl context, so recreate it.
473            if (!isEnabled()) {
474                if (initialize(surface)) {
475                    setup(width, height, attachInfo, surfaceInsets);
476                    return true;
477                }
478            }
479        }
480        return false;
481    }
482
483    /**
484     * Updates the hardware renderer for the specified surface.
485     *
486     * @param surface The surface to hardware accelerate
487     */
488    void updateSurface(Surface surface) throws OutOfResourcesException {
489        updateEnabledState(surface);
490        nUpdateSurface(mNativeProxy, surface);
491    }
492
493    /**
494     * Halts any current rendering into the surface. Use this if it is unclear whether
495     * or not the surface used by the HardwareRenderer will be changing. It
496     * Suspends any rendering into the surface, but will not do any destruction.
497     *
498     * Any subsequent draws will override the pause, resuming normal operation.
499     */
500    boolean pauseSurface(Surface surface) {
501        return nPauseSurface(mNativeProxy, surface);
502    }
503
504    /**
505     * Hard stops or resumes rendering into the surface. This flag is used to
506     * determine whether or not it is safe to use the given surface *at all*
507     */
508    void setStopped(boolean stopped) {
509        nSetStopped(mNativeProxy, stopped);
510    }
511
512    /**
513     * Destroys all hardware rendering resources associated with the specified
514     * view hierarchy.
515     *
516     * @param view The root of the view hierarchy
517     */
518    void destroyHardwareResources(View view) {
519        destroyResources(view);
520        nDestroyHardwareResources(mNativeProxy);
521    }
522
523    private static void destroyResources(View view) {
524        view.destroyHardwareResources();
525
526        if (view instanceof ViewGroup) {
527            ViewGroup group = (ViewGroup) view;
528
529            int count = group.getChildCount();
530            for (int i = 0; i < count; i++) {
531                destroyResources(group.getChildAt(i));
532            }
533        }
534    }
535
536    /**
537     * This method should be invoked whenever the current hardware renderer
538     * context should be reset.
539     *
540     * @param surface The surface to hardware accelerate
541     */
542    void invalidate(Surface surface) {
543        updateSurface(surface);
544    }
545
546    /**
547     * Detaches the layer's surface texture from the GL context and releases
548     * the texture id
549     */
550    void detachSurfaceTexture(long hardwareLayer) {
551        nDetachSurfaceTexture(mNativeProxy, hardwareLayer);
552    }
553
554    /**
555     * Sets up the renderer for drawing.
556     *
557     * @param width The width of the drawing surface.
558     * @param height The height of the drawing surface.
559     * @param attachInfo Information about the window.
560     * @param surfaceInsets The drawing surface insets to apply
561     */
562    void setup(int width, int height, AttachInfo attachInfo, Rect surfaceInsets) {
563        mWidth = width;
564        mHeight = height;
565
566        if (surfaceInsets != null && (surfaceInsets.left != 0 || surfaceInsets.right != 0
567                || surfaceInsets.top != 0 || surfaceInsets.bottom != 0)) {
568            mHasInsets = true;
569            mInsetLeft = surfaceInsets.left;
570            mInsetTop = surfaceInsets.top;
571            mSurfaceWidth = width + mInsetLeft + surfaceInsets.right;
572            mSurfaceHeight = height + mInsetTop + surfaceInsets.bottom;
573
574            // If the surface has insets, it can't be opaque.
575            setOpaque(false);
576        } else {
577            mHasInsets = false;
578            mInsetLeft = 0;
579            mInsetTop = 0;
580            mSurfaceWidth = width;
581            mSurfaceHeight = height;
582        }
583
584        mRootNode.setLeftTopRightBottom(-mInsetLeft, -mInsetTop, mSurfaceWidth, mSurfaceHeight);
585        nSetup(mNativeProxy, mSurfaceWidth, mSurfaceHeight, mLightRadius,
586                mAmbientShadowAlpha, mSpotShadowAlpha);
587
588        setLightCenter(attachInfo);
589    }
590
591    /**
592     * Updates the light position based on the position of the window.
593     *
594     * @param attachInfo Information about the window.
595     */
596    void setLightCenter(AttachInfo attachInfo) {
597        // Adjust light position for window offsets.
598        final Point displaySize = attachInfo.mPoint;
599        attachInfo.mDisplay.getRealSize(displaySize);
600        final float lightX = displaySize.x / 2f - attachInfo.mWindowLeft;
601        final float lightY = mLightY - attachInfo.mWindowTop;
602
603        nSetLightCenter(mNativeProxy, lightX, lightY, mLightZ);
604    }
605
606    /**
607     * Change the HardwareRenderer's opacity
608     */
609    void setOpaque(boolean opaque) {
610        nSetOpaque(mNativeProxy, opaque && !mHasInsets);
611    }
612
613    /**
614     * Gets the current width of the surface. This is the width that the surface
615     * was last set to in a call to {@link #setup(int, int, View.AttachInfo, Rect)}.
616     *
617     * @return the current width of the surface
618     */
619    int getWidth() {
620        return mWidth;
621    }
622
623    /**
624     * Gets the current height of the surface. This is the height that the surface
625     * was last set to in a call to {@link #setup(int, int, View.AttachInfo, Rect)}.
626     *
627     * @return the current width of the surface
628     */
629    int getHeight() {
630        return mHeight;
631    }
632
633    /**
634     * Outputs extra debugging information in the specified file descriptor.
635     */
636    void dumpGfxInfo(PrintWriter pw, FileDescriptor fd, String[] args) {
637        pw.flush();
638        int flags = 0;
639        for (int i = 0; i < args.length; i++) {
640            switch (args[i]) {
641                case "framestats":
642                    flags |= FLAG_DUMP_FRAMESTATS;
643                    break;
644                case "reset":
645                    flags |= FLAG_DUMP_RESET;
646                    break;
647            }
648        }
649        nDumpProfileInfo(mNativeProxy, fd, flags);
650    }
651
652    /**
653     * Loads system properties used by the renderer. This method is invoked
654     * whenever system properties are modified. Implementations can use this
655     * to trigger live updates of the renderer based on properties.
656     *
657     * @return True if a property has changed.
658     */
659    boolean loadSystemProperties() {
660        boolean changed = nLoadSystemProperties(mNativeProxy);
661        if (changed) {
662            invalidateRoot();
663        }
664        return changed;
665    }
666
667    private void updateViewTreeDisplayList(View view) {
668        view.mPrivateFlags |= View.PFLAG_DRAWN;
669        view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
670                == View.PFLAG_INVALIDATED;
671        view.mPrivateFlags &= ~View.PFLAG_INVALIDATED;
672        view.updateDisplayListIfDirty();
673        view.mRecreateDisplayList = false;
674    }
675
676    private void updateRootDisplayList(View view, HardwareDrawCallbacks callbacks) {
677        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Record View#draw()");
678        updateViewTreeDisplayList(view);
679
680        if (mRootNodeNeedsUpdate || !mRootNode.isValid()) {
681            DisplayListCanvas canvas = mRootNode.start(mSurfaceWidth, mSurfaceHeight);
682            try {
683                final int saveCount = canvas.save();
684                canvas.translate(mInsetLeft, mInsetTop);
685                callbacks.onHardwarePreDraw(canvas);
686
687                canvas.insertReorderBarrier();
688                canvas.drawRenderNode(view.updateDisplayListIfDirty());
689                canvas.insertInorderBarrier();
690
691                callbacks.onHardwarePostDraw(canvas);
692                canvas.restoreToCount(saveCount);
693                mRootNodeNeedsUpdate = false;
694            } finally {
695                mRootNode.end(canvas);
696            }
697        }
698        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
699    }
700
701    /**
702     * Adds a rendernode to the renderer which can be drawn and changed asynchronously to the
703     * rendernode of the UI thread.
704     * @param node The node to add.
705     * @param placeFront If true, the render node will be placed in front of the content node,
706     *                   otherwise behind the content node.
707     */
708    public void addRenderNode(RenderNode node, boolean placeFront) {
709        nAddRenderNode(mNativeProxy, node.mNativeRenderNode, placeFront);
710    }
711
712    /**
713     * Only especially added render nodes can be removed.
714     * @param node The node which was added via addRenderNode which should get removed again.
715     */
716    public void removeRenderNode(RenderNode node) {
717        nRemoveRenderNode(mNativeProxy, node.mNativeRenderNode);
718    }
719
720    /**
721     * Draws a particular render node. If the node is not the content node, only the additional
722     * nodes will get drawn and the content remains untouched.
723     * @param node The node to be drawn.
724     */
725    public void drawRenderNode(RenderNode node) {
726        nDrawRenderNode(mNativeProxy, node.mNativeRenderNode);
727    }
728
729    /**
730     * To avoid unnecessary overdrawing of the main content all additionally passed render nodes
731     * will be prevented to overdraw this area. It will be synchronized with the draw call.
732     * This should be updated in the content view's draw call.
733     * @param left The left side of the protected bounds.
734     * @param top The top side of the protected bounds.
735     * @param right The right side of the protected bounds.
736     * @param bottom The bottom side of the protected bounds.
737     */
738    public void setContentDrawBounds(int left, int top, int right, int bottom) {
739        mStagedContentBounds.set(left, top, right, bottom);
740    }
741
742    /**
743     * Interface used to receive callbacks whenever a view is drawn by
744     * a hardware renderer instance.
745     */
746    interface HardwareDrawCallbacks {
747        /**
748         * Invoked before a view is drawn by a hardware renderer.
749         * This method can be used to apply transformations to the
750         * canvas but no drawing command should be issued.
751         *
752         * @param canvas The Canvas used to render the view.
753         */
754        void onHardwarePreDraw(DisplayListCanvas canvas);
755
756        /**
757         * Invoked after a view is drawn by a hardware renderer.
758         * It is safe to invoke drawing commands from this method.
759         *
760         * @param canvas The Canvas used to render the view.
761         */
762        void onHardwarePostDraw(DisplayListCanvas canvas);
763    }
764
765    /**
766     *  Indicates that the content drawn by HardwareDrawCallbacks needs to
767     *  be updated, which will be done by the next call to draw()
768     */
769    void invalidateRoot() {
770        mRootNodeNeedsUpdate = true;
771    }
772
773    /**
774     * Draws the specified view.
775     *
776     * @param view The view to draw.
777     * @param attachInfo AttachInfo tied to the specified view.
778     * @param callbacks Callbacks invoked when drawing happens.
779     */
780    void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks) {
781        attachInfo.mIgnoreDirtyState = true;
782
783        final Choreographer choreographer = attachInfo.mViewRootImpl.mChoreographer;
784        choreographer.mFrameInfo.markDrawStart();
785
786        updateRootDisplayList(view, callbacks);
787        // The main content view was updating the content bounds and we transfer them to the
788        // renderer.
789        if (!mCurrentContentBounds.equals(mStagedContentBounds)) {
790            mCurrentContentBounds.set(mStagedContentBounds);
791            nSetContentDrawBounds(mNativeProxy, mCurrentContentBounds.left,
792                    mCurrentContentBounds.top, mCurrentContentBounds.right,
793                    mCurrentContentBounds.bottom);
794        }
795
796        attachInfo.mIgnoreDirtyState = false;
797
798        // register animating rendernodes which started animating prior to renderer
799        // creation, which is typical for animators started prior to first draw
800        if (attachInfo.mPendingAnimatingRenderNodes != null) {
801            final int count = attachInfo.mPendingAnimatingRenderNodes.size();
802            for (int i = 0; i < count; i++) {
803                registerAnimatingRenderNode(
804                        attachInfo.mPendingAnimatingRenderNodes.get(i));
805            }
806            attachInfo.mPendingAnimatingRenderNodes.clear();
807            // We don't need this anymore as subsequent calls to
808            // ViewRootImpl#attachRenderNodeAnimator will go directly to us.
809            attachInfo.mPendingAnimatingRenderNodes = null;
810        }
811
812        final long[] frameInfo = choreographer.mFrameInfo.mFrameInfo;
813        int syncResult = nSyncAndDrawFrame(mNativeProxy, frameInfo, frameInfo.length);
814        if ((syncResult & SYNC_LOST_SURFACE_REWARD_IF_FOUND) != 0) {
815            setEnabled(false);
816            attachInfo.mViewRootImpl.mSurface.release();
817            // Invalidate since we failed to draw. This should fetch a Surface
818            // if it is still needed or do nothing if we are no longer drawing
819            attachInfo.mViewRootImpl.invalidate();
820        }
821        if ((syncResult & SYNC_INVALIDATE_REQUIRED) != 0) {
822            attachInfo.mViewRootImpl.invalidate();
823        }
824    }
825
826    static void invokeFunctor(long functor, boolean waitForCompletion) {
827        nInvokeFunctor(functor, waitForCompletion);
828    }
829
830    /**
831     * Creates a new hardware layer. A hardware layer built by calling this
832     * method will be treated as a texture layer, instead of as a render target.
833     *
834     * @return A hardware layer
835     */
836    HardwareLayer createTextureLayer() {
837        long layer = nCreateTextureLayer(mNativeProxy);
838        return HardwareLayer.adoptTextureLayer(this, layer);
839    }
840
841
842    void buildLayer(RenderNode node) {
843        nBuildLayer(mNativeProxy, node.getNativeDisplayList());
844    }
845
846
847    boolean copyLayerInto(final HardwareLayer layer, final Bitmap bitmap) {
848        return nCopyLayerInto(mNativeProxy,
849                layer.getDeferredLayerUpdater(), bitmap);
850    }
851
852    /**
853     * Indicates that the specified hardware layer needs to be updated
854     * as soon as possible.
855     *
856     * @param layer The hardware layer that needs an update
857     */
858    void pushLayerUpdate(HardwareLayer layer) {
859        nPushLayerUpdate(mNativeProxy, layer.getDeferredLayerUpdater());
860    }
861
862    /**
863     * Tells the HardwareRenderer that the layer is destroyed. The renderer
864     * should remove the layer from any update queues.
865     */
866    void onLayerDestroyed(HardwareLayer layer) {
867        nCancelLayerUpdate(mNativeProxy, layer.getDeferredLayerUpdater());
868    }
869
870    /**
871     * Optional, sets the name of the renderer. Useful for debugging purposes.
872     *
873     * @param name The name of this renderer, can be null
874     */
875    void setName(String name) {
876        nSetName(mNativeProxy, name);
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    public void serializeDisplayListTree() {
909        nSerializeDisplayListTree(mNativeProxy);
910    }
911
912    public static boolean copySurfaceInto(Surface surface, Bitmap bitmap) {
913        return nCopySurfaceInto(surface, bitmap);
914    }
915
916    @Override
917    protected void finalize() throws Throwable {
918        try {
919            nDeleteProxy(mNativeProxy);
920            mNativeProxy = 0;
921        } finally {
922            super.finalize();
923        }
924    }
925
926    private static class ProcessInitializer {
927        static ProcessInitializer sInstance = new ProcessInitializer();
928        private static IBinder sProcToken;
929
930        private boolean mInitialized = false;
931
932        private ProcessInitializer() {}
933
934        synchronized void init(Context context, long renderProxy) {
935            if (mInitialized) return;
936            mInitialized = true;
937            initGraphicsStats(context, renderProxy);
938            initAssetAtlas(context, renderProxy);
939        }
940
941        private static void initGraphicsStats(Context context, long renderProxy) {
942            try {
943                IBinder binder = ServiceManager.getService("graphicsstats");
944                if (binder == null) return;
945                IGraphicsStats graphicsStatsService = IGraphicsStats.Stub
946                        .asInterface(binder);
947                sProcToken = new Binder();
948                final String pkg = context.getApplicationInfo().packageName;
949                ParcelFileDescriptor pfd = graphicsStatsService.
950                        requestBufferForProcess(pkg, sProcToken);
951                nSetProcessStatsBuffer(renderProxy, pfd.getFd());
952                pfd.close();
953            } catch (Throwable t) {
954                Log.w(LOG_TAG, "Could not acquire gfx stats buffer", t);
955            }
956        }
957
958        private static void initAssetAtlas(Context context, long renderProxy) {
959            IBinder binder = ServiceManager.getService("assetatlas");
960            if (binder == null) return;
961
962            IAssetAtlas atlas = IAssetAtlas.Stub.asInterface(binder);
963            try {
964                if (atlas.isCompatible(android.os.Process.myPpid())) {
965                    GraphicBuffer buffer = atlas.getBuffer();
966                    if (buffer != null) {
967                        long[] map = atlas.getMap();
968                        if (map != null) {
969                            nSetAtlas(renderProxy, buffer, map);
970                        }
971                        // If IAssetAtlas is not the same class as the IBinder
972                        // we are using a remote service and we can safely
973                        // destroy the graphic buffer
974                        if (atlas.getClass() != binder.getClass()) {
975                            buffer.destroy();
976                        }
977                    }
978                }
979            } catch (RemoteException e) {
980                Log.w(LOG_TAG, "Could not acquire atlas", e);
981            }
982        }
983    }
984
985    void addFrameMetricsObserver(FrameMetricsObserver observer) {
986        long nativeObserver = nAddFrameMetricsObserver(mNativeProxy, observer);
987        observer.mNative = new VirtualRefBasePtr(nativeObserver);
988    }
989
990    void removeFrameMetricsObserver(FrameMetricsObserver observer) {
991        nRemoveFrameMetricsObserver(mNativeProxy, observer.mNative.get());
992        observer.mNative = null;
993    }
994
995    static native void setupShadersDiskCache(String cacheFile);
996    static native void setupVulkanLayerPath(String layerPath);
997
998    private static native void nSetAtlas(long nativeProxy, GraphicBuffer buffer, long[] map);
999    private static native void nSetProcessStatsBuffer(long nativeProxy, int fd);
1000
1001    private static native long nCreateRootRenderNode();
1002    private static native long nCreateProxy(boolean translucent, long rootRenderNode);
1003    private static native void nDeleteProxy(long nativeProxy);
1004
1005    private static native boolean nLoadSystemProperties(long nativeProxy);
1006    private static native void nSetName(long nativeProxy, String name);
1007
1008    private static native void nInitialize(long nativeProxy, Surface window);
1009    private static native void nUpdateSurface(long nativeProxy, Surface window);
1010    private static native boolean nPauseSurface(long nativeProxy, Surface window);
1011    private static native void nSetStopped(long nativeProxy, boolean stopped);
1012    private static native void nSetup(long nativeProxy, int width, int height,
1013            float lightRadius, int ambientShadowAlpha, int spotShadowAlpha);
1014    private static native void nSetLightCenter(long nativeProxy,
1015            float lightX, float lightY, float lightZ);
1016    private static native void nSetOpaque(long nativeProxy, boolean opaque);
1017    private static native int nSyncAndDrawFrame(long nativeProxy, long[] frameInfo, int size);
1018    private static native void nDestroy(long nativeProxy, long rootRenderNode);
1019    private static native void nRegisterAnimatingRenderNode(long rootRenderNode, long animatingNode);
1020
1021    private static native void nInvokeFunctor(long functor, boolean waitForCompletion);
1022
1023    private static native long nCreateTextureLayer(long nativeProxy);
1024    private static native void nBuildLayer(long nativeProxy, long node);
1025    private static native boolean nCopyLayerInto(long nativeProxy, long layer, Bitmap bitmap);
1026    private static native void nPushLayerUpdate(long nativeProxy, long layer);
1027    private static native void nCancelLayerUpdate(long nativeProxy, long layer);
1028    private static native void nDetachSurfaceTexture(long nativeProxy, long layer);
1029
1030    private static native void nDestroyHardwareResources(long nativeProxy);
1031    private static native void nTrimMemory(int level);
1032    private static native void nOverrideProperty(String name, String value);
1033
1034    private static native void nFence(long nativeProxy);
1035    private static native void nStopDrawing(long nativeProxy);
1036    private static native void nNotifyFramePending(long nativeProxy);
1037
1038    private static native void nSerializeDisplayListTree(long nativeProxy);
1039
1040    private static native void nDumpProfileInfo(long nativeProxy, FileDescriptor fd,
1041            @DumpFlags int dumpFlags);
1042    private static native void nDumpProfileData(byte[] data, FileDescriptor fd);
1043
1044    private static native void nAddRenderNode(long nativeProxy, long rootRenderNode,
1045             boolean placeFront);
1046    private static native void nRemoveRenderNode(long nativeProxy, long rootRenderNode);
1047    private static native void nDrawRenderNode(long nativeProxy, long rootRenderNode);
1048    private static native void nSetContentDrawBounds(long nativeProxy, int left,
1049             int top, int right, int bottom);
1050
1051    private static native long nAddFrameMetricsObserver(long nativeProxy, FrameMetricsObserver observer);
1052    private static native void nRemoveFrameMetricsObserver(long nativeProxy, long nativeObserver);
1053
1054    private static native boolean nCopySurfaceInto(Surface surface, Bitmap bitmap);
1055}
1056