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     * Creates a hardware renderer using OpenGL.
256     *
257     * @param translucent True if the surface is translucent, false otherwise
258     *
259     * @return A hardware renderer backed by OpenGL.
260     */
261    public static ThreadedRenderer create(Context context, boolean translucent) {
262        ThreadedRenderer renderer = null;
263        if (DisplayListCanvas.isAvailable()) {
264            renderer = new ThreadedRenderer(context, translucent);
265        }
266        return renderer;
267    }
268
269    /**
270     * Invoke this method when the system is running out of memory. This
271     * method will attempt to recover as much memory as possible, based on
272     * the specified hint.
273     *
274     * @param level Hint about the amount of memory that should be trimmed,
275     *              see {@link android.content.ComponentCallbacks}
276     */
277    public static void trimMemory(int level) {
278        nTrimMemory(level);
279    }
280
281    public static void overrideProperty(@NonNull String name, @NonNull String value) {
282        if (name == null || value == null) {
283            throw new IllegalArgumentException("name and value must be non-null");
284        }
285        nOverrideProperty(name, value);
286    }
287
288    public static void dumpProfileData(byte[] data, FileDescriptor fd) {
289        nDumpProfileData(data, fd);
290    }
291
292    // Keep in sync with DrawFrameTask.h SYNC_* flags
293    // Nothing interesting to report
294    private static final int SYNC_OK = 0;
295    // Needs a ViewRoot invalidate
296    private static final int SYNC_INVALIDATE_REQUIRED = 1 << 0;
297    // Spoiler: the reward is GPU-accelerated drawing, better find that Surface!
298    private static final int SYNC_LOST_SURFACE_REWARD_IF_FOUND = 1 << 1;
299    // setStopped is true, drawing is false
300    // TODO: Remove this and SYNC_LOST_SURFACE_REWARD_IF_FOUND?
301    // This flag isn't really used as there's nothing that we care to do
302    // in response, so it really just exists to differentiate from LOST_SURFACE
303    // but possibly both can just be deleted.
304    private static final int SYNC_CONTEXT_IS_STOPPED = 1 << 2;
305
306    private static final String[] VISUALIZERS = {
307        PROFILE_PROPERTY_VISUALIZE_BARS,
308    };
309
310    private static final int FLAG_DUMP_FRAMESTATS   = 1 << 0;
311    private static final int FLAG_DUMP_RESET        = 1 << 1;
312
313    @IntDef(flag = true, value = {
314            FLAG_DUMP_FRAMESTATS, FLAG_DUMP_RESET })
315    @Retention(RetentionPolicy.SOURCE)
316    public @interface DumpFlags {}
317
318    // Size of the rendered content.
319    private int mWidth, mHeight;
320
321    // Actual size of the drawing surface.
322    private int mSurfaceWidth, mSurfaceHeight;
323
324    // Insets between the drawing surface and rendered content. These are
325    // applied as translation when updating the root render node.
326    private int mInsetTop, mInsetLeft;
327
328    // Whether the surface has insets. Used to protect opacity.
329    private boolean mHasInsets;
330
331    // Light and shadow properties specified by the theme.
332    private final float mLightY;
333    private final float mLightZ;
334    private final float mLightRadius;
335    private final int mAmbientShadowAlpha;
336    private final int mSpotShadowAlpha;
337
338    private long mNativeProxy;
339    private boolean mInitialized = false;
340    private RenderNode mRootNode;
341    private Choreographer mChoreographer;
342    private boolean mRootNodeNeedsUpdate;
343
344    private boolean mEnabled;
345    private boolean mRequested = true;
346
347    ThreadedRenderer(Context context, boolean translucent) {
348        final TypedArray a = context.obtainStyledAttributes(null, R.styleable.Lighting, 0, 0);
349        mLightY = a.getDimension(R.styleable.Lighting_lightY, 0);
350        mLightZ = a.getDimension(R.styleable.Lighting_lightZ, 0);
351        mLightRadius = a.getDimension(R.styleable.Lighting_lightRadius, 0);
352        mAmbientShadowAlpha =
353                (int) (255 * a.getFloat(R.styleable.Lighting_ambientShadowAlpha, 0) + 0.5f);
354        mSpotShadowAlpha = (int) (255 * a.getFloat(R.styleable.Lighting_spotShadowAlpha, 0) + 0.5f);
355        a.recycle();
356
357        long rootNodePtr = nCreateRootRenderNode();
358        mRootNode = RenderNode.adopt(rootNodePtr);
359        mRootNode.setClipToBounds(false);
360        mNativeProxy = nCreateProxy(translucent, rootNodePtr);
361
362        ProcessInitializer.sInstance.init(context, mNativeProxy);
363
364        loadSystemProperties();
365    }
366
367    /**
368     * Destroys the hardware rendering context.
369     */
370    void destroy() {
371        mInitialized = false;
372        updateEnabledState(null);
373        nDestroy(mNativeProxy, mRootNode.mNativeRenderNode);
374    }
375
376    /**
377     * Indicates whether hardware acceleration is currently enabled.
378     *
379     * @return True if hardware acceleration is in use, false otherwise.
380     */
381    boolean isEnabled() {
382        return mEnabled;
383    }
384
385    /**
386     * Indicates whether hardware acceleration is currently enabled.
387     *
388     * @param enabled True if the hardware renderer is in use, false otherwise.
389     */
390    void setEnabled(boolean enabled) {
391        mEnabled = enabled;
392    }
393
394    /**
395     * Indicates whether hardware acceleration is currently request but not
396     * necessarily enabled yet.
397     *
398     * @return True if requested, false otherwise.
399     */
400    boolean isRequested() {
401        return mRequested;
402    }
403
404    /**
405     * Indicates whether hardware acceleration is currently requested but not
406     * necessarily enabled yet.
407     *
408     * @return True to request hardware acceleration, false otherwise.
409     */
410    void setRequested(boolean requested) {
411        mRequested = requested;
412    }
413
414    private void updateEnabledState(Surface surface) {
415        if (surface == null || !surface.isValid()) {
416            setEnabled(false);
417        } else {
418            setEnabled(mInitialized);
419        }
420    }
421
422    /**
423     * Initializes the hardware renderer for the specified surface.
424     *
425     * @param surface The surface to hardware accelerate
426     *
427     * @return True if the initialization was successful, false otherwise.
428     */
429    boolean initialize(Surface surface) throws OutOfResourcesException {
430        boolean status = !mInitialized;
431        mInitialized = true;
432        updateEnabledState(surface);
433        nInitialize(mNativeProxy, surface);
434        return status;
435    }
436
437    /**
438     * Initializes the hardware renderer for the specified surface and setup the
439     * renderer for drawing, if needed. This is invoked when the ViewAncestor has
440     * potentially lost the hardware renderer. The hardware renderer should be
441     * reinitialized and setup when the render {@link #isRequested()} and
442     * {@link #isEnabled()}.
443     *
444     * @param width The width of the drawing surface.
445     * @param height The height of the drawing surface.
446     * @param attachInfo Information about the window.
447     * @param surface The surface to hardware accelerate
448     * @param surfaceInsets The drawing surface insets to apply
449     *
450     * @return true if the surface was initialized, false otherwise. Returning
451     *         false might mean that the surface was already initialized.
452     */
453    boolean initializeIfNeeded(int width, int height, View.AttachInfo attachInfo,
454            Surface surface, Rect surfaceInsets) throws OutOfResourcesException {
455        if (isRequested()) {
456            // We lost the gl context, so recreate it.
457            if (!isEnabled()) {
458                if (initialize(surface)) {
459                    setup(width, height, attachInfo, surfaceInsets);
460                    return true;
461                }
462            }
463        }
464        return false;
465    }
466
467    /**
468     * Updates the hardware renderer for the specified surface.
469     *
470     * @param surface The surface to hardware accelerate
471     */
472    void updateSurface(Surface surface) throws OutOfResourcesException {
473        updateEnabledState(surface);
474        nUpdateSurface(mNativeProxy, surface);
475    }
476
477    /**
478     * Halts any current rendering into the surface. Use this if it is unclear whether
479     * or not the surface used by the HardwareRenderer will be changing. It
480     * Suspends any rendering into the surface, but will not do any destruction.
481     *
482     * Any subsequent draws will override the pause, resuming normal operation.
483     */
484    boolean pauseSurface(Surface surface) {
485        return nPauseSurface(mNativeProxy, surface);
486    }
487
488    /**
489     * Hard stops or resumes rendering into the surface. This flag is used to
490     * determine whether or not it is safe to use the given surface *at all*
491     */
492    void setStopped(boolean stopped) {
493        nSetStopped(mNativeProxy, stopped);
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        nSetContentDrawBounds(mNativeProxy, 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
772        attachInfo.mIgnoreDirtyState = false;
773
774        // register animating rendernodes which started animating prior to renderer
775        // creation, which is typical for animators started prior to first draw
776        if (attachInfo.mPendingAnimatingRenderNodes != null) {
777            final int count = attachInfo.mPendingAnimatingRenderNodes.size();
778            for (int i = 0; i < count; i++) {
779                registerAnimatingRenderNode(
780                        attachInfo.mPendingAnimatingRenderNodes.get(i));
781            }
782            attachInfo.mPendingAnimatingRenderNodes.clear();
783            // We don't need this anymore as subsequent calls to
784            // ViewRootImpl#attachRenderNodeAnimator will go directly to us.
785            attachInfo.mPendingAnimatingRenderNodes = null;
786        }
787
788        final long[] frameInfo = choreographer.mFrameInfo.mFrameInfo;
789        int syncResult = nSyncAndDrawFrame(mNativeProxy, frameInfo, frameInfo.length);
790        if ((syncResult & SYNC_LOST_SURFACE_REWARD_IF_FOUND) != 0) {
791            setEnabled(false);
792            attachInfo.mViewRootImpl.mSurface.release();
793            // Invalidate since we failed to draw. This should fetch a Surface
794            // if it is still needed or do nothing if we are no longer drawing
795            attachInfo.mViewRootImpl.invalidate();
796        }
797        if ((syncResult & SYNC_INVALIDATE_REQUIRED) != 0) {
798            attachInfo.mViewRootImpl.invalidate();
799        }
800    }
801
802    static void invokeFunctor(long functor, boolean waitForCompletion) {
803        nInvokeFunctor(functor, waitForCompletion);
804    }
805
806    /**
807     * Creates a new hardware layer. A hardware layer built by calling this
808     * method will be treated as a texture layer, instead of as a render target.
809     *
810     * @return A hardware layer
811     */
812    HardwareLayer createTextureLayer() {
813        long layer = nCreateTextureLayer(mNativeProxy);
814        return HardwareLayer.adoptTextureLayer(this, layer);
815    }
816
817
818    void buildLayer(RenderNode node) {
819        nBuildLayer(mNativeProxy, node.getNativeDisplayList());
820    }
821
822
823    boolean copyLayerInto(final HardwareLayer layer, final Bitmap bitmap) {
824        return nCopyLayerInto(mNativeProxy,
825                layer.getDeferredLayerUpdater(), bitmap);
826    }
827
828    /**
829     * Indicates that the specified hardware layer needs to be updated
830     * as soon as possible.
831     *
832     * @param layer The hardware layer that needs an update
833     */
834    void pushLayerUpdate(HardwareLayer layer) {
835        nPushLayerUpdate(mNativeProxy, layer.getDeferredLayerUpdater());
836    }
837
838    /**
839     * Tells the HardwareRenderer that the layer is destroyed. The renderer
840     * should remove the layer from any update queues.
841     */
842    void onLayerDestroyed(HardwareLayer layer) {
843        nCancelLayerUpdate(mNativeProxy, layer.getDeferredLayerUpdater());
844    }
845
846    /**
847     * Optional, sets the name of the renderer. Useful for debugging purposes.
848     *
849     * @param name The name of this renderer, can be null
850     */
851    void setName(String name) {
852        nSetName(mNativeProxy, name);
853    }
854
855    /**
856     * Blocks until all previously queued work has completed.
857     */
858    void fence() {
859        nFence(mNativeProxy);
860    }
861
862    /**
863     * Prevents any further drawing until draw() is called. This is a signal
864     * that the contents of the RenderNode tree are no longer safe to play back.
865     * In practice this usually means that there are Functor pointers in the
866     * display list that are no longer valid.
867     */
868    void stopDrawing() {
869        nStopDrawing(mNativeProxy);
870    }
871
872    /**
873     * Called by {@link ViewRootImpl} when a new performTraverals is scheduled.
874     */
875    public void notifyFramePending() {
876        nNotifyFramePending(mNativeProxy);
877    }
878
879
880    void registerAnimatingRenderNode(RenderNode animator) {
881        nRegisterAnimatingRenderNode(mRootNode.mNativeRenderNode, animator.mNativeRenderNode);
882    }
883
884    public void serializeDisplayListTree() {
885        nSerializeDisplayListTree(mNativeProxy);
886    }
887
888    public static int copySurfaceInto(Surface surface, Bitmap bitmap) {
889        return nCopySurfaceInto(surface, bitmap);
890    }
891
892    @Override
893    protected void finalize() throws Throwable {
894        try {
895            nDeleteProxy(mNativeProxy);
896            mNativeProxy = 0;
897        } finally {
898            super.finalize();
899        }
900    }
901
902    private static class ProcessInitializer {
903        static ProcessInitializer sInstance = new ProcessInitializer();
904        private static IBinder sProcToken;
905
906        private boolean mInitialized = false;
907
908        private ProcessInitializer() {}
909
910        synchronized void init(Context context, long renderProxy) {
911            if (mInitialized) return;
912            mInitialized = true;
913            initGraphicsStats(context, renderProxy);
914            initAssetAtlas(context, renderProxy);
915        }
916
917        private static void initGraphicsStats(Context context, long renderProxy) {
918            try {
919                IBinder binder = ServiceManager.getService("graphicsstats");
920                if (binder == null) return;
921                IGraphicsStats graphicsStatsService = IGraphicsStats.Stub
922                        .asInterface(binder);
923                sProcToken = new Binder();
924                final String pkg = context.getApplicationInfo().packageName;
925                ParcelFileDescriptor pfd = graphicsStatsService.
926                        requestBufferForProcess(pkg, sProcToken);
927                nSetProcessStatsBuffer(renderProxy, pfd.getFd());
928                pfd.close();
929            } catch (Throwable t) {
930                Log.w(LOG_TAG, "Could not acquire gfx stats buffer", t);
931            }
932        }
933
934        private static void initAssetAtlas(Context context, long renderProxy) {
935            IBinder binder = ServiceManager.getService("assetatlas");
936            if (binder == null) return;
937
938            IAssetAtlas atlas = IAssetAtlas.Stub.asInterface(binder);
939            try {
940                if (atlas.isCompatible(android.os.Process.myPpid())) {
941                    GraphicBuffer buffer = atlas.getBuffer();
942                    if (buffer != null) {
943                        long[] map = atlas.getMap();
944                        if (map != null) {
945                            nSetAtlas(renderProxy, buffer, map);
946                        }
947                        // If IAssetAtlas is not the same class as the IBinder
948                        // we are using a remote service and we can safely
949                        // destroy the graphic buffer
950                        if (atlas.getClass() != binder.getClass()) {
951                            buffer.destroy();
952                        }
953                    }
954                }
955            } catch (RemoteException e) {
956                Log.w(LOG_TAG, "Could not acquire atlas", e);
957            }
958        }
959    }
960
961    void addFrameMetricsObserver(FrameMetricsObserver observer) {
962        long nativeObserver = nAddFrameMetricsObserver(mNativeProxy, observer);
963        observer.mNative = new VirtualRefBasePtr(nativeObserver);
964    }
965
966    void removeFrameMetricsObserver(FrameMetricsObserver observer) {
967        nRemoveFrameMetricsObserver(mNativeProxy, observer.mNative.get());
968        observer.mNative = null;
969    }
970
971    static native void setupShadersDiskCache(String cacheFile);
972
973    private static native void nSetAtlas(long nativeProxy, GraphicBuffer buffer, long[] map);
974    private static native void nSetProcessStatsBuffer(long nativeProxy, int fd);
975
976    private static native long nCreateRootRenderNode();
977    private static native long nCreateProxy(boolean translucent, long rootRenderNode);
978    private static native void nDeleteProxy(long nativeProxy);
979
980    private static native boolean nLoadSystemProperties(long nativeProxy);
981    private static native void nSetName(long nativeProxy, String name);
982
983    private static native void nInitialize(long nativeProxy, Surface window);
984    private static native void nUpdateSurface(long nativeProxy, Surface window);
985    private static native boolean nPauseSurface(long nativeProxy, Surface window);
986    private static native void nSetStopped(long nativeProxy, boolean stopped);
987    private static native void nSetup(long nativeProxy, int width, int height,
988            float lightRadius, int ambientShadowAlpha, int spotShadowAlpha);
989    private static native void nSetLightCenter(long nativeProxy,
990            float lightX, float lightY, float lightZ);
991    private static native void nSetOpaque(long nativeProxy, boolean opaque);
992    private static native int nSyncAndDrawFrame(long nativeProxy, long[] frameInfo, int size);
993    private static native void nDestroy(long nativeProxy, long rootRenderNode);
994    private static native void nRegisterAnimatingRenderNode(long rootRenderNode, long animatingNode);
995
996    private static native void nInvokeFunctor(long functor, boolean waitForCompletion);
997
998    private static native long nCreateTextureLayer(long nativeProxy);
999    private static native void nBuildLayer(long nativeProxy, long node);
1000    private static native boolean nCopyLayerInto(long nativeProxy, long layer, Bitmap bitmap);
1001    private static native void nPushLayerUpdate(long nativeProxy, long layer);
1002    private static native void nCancelLayerUpdate(long nativeProxy, long layer);
1003    private static native void nDetachSurfaceTexture(long nativeProxy, long layer);
1004
1005    private static native void nDestroyHardwareResources(long nativeProxy);
1006    private static native void nTrimMemory(int level);
1007    private static native void nOverrideProperty(String name, String value);
1008
1009    private static native void nFence(long nativeProxy);
1010    private static native void nStopDrawing(long nativeProxy);
1011    private static native void nNotifyFramePending(long nativeProxy);
1012
1013    private static native void nSerializeDisplayListTree(long nativeProxy);
1014
1015    private static native void nDumpProfileInfo(long nativeProxy, FileDescriptor fd,
1016            @DumpFlags int dumpFlags);
1017    private static native void nDumpProfileData(byte[] data, FileDescriptor fd);
1018
1019    private static native void nAddRenderNode(long nativeProxy, long rootRenderNode,
1020             boolean placeFront);
1021    private static native void nRemoveRenderNode(long nativeProxy, long rootRenderNode);
1022    private static native void nDrawRenderNode(long nativeProxy, long rootRenderNode);
1023    private static native void nSetContentDrawBounds(long nativeProxy, int left,
1024             int top, int right, int bottom);
1025
1026    private static native long nAddFrameMetricsObserver(long nativeProxy, FrameMetricsObserver observer);
1027    private static native void nRemoveFrameMetricsObserver(long nativeProxy, long nativeObserver);
1028
1029    private static native int nCopySurfaceInto(Surface surface, Bitmap bitmap);
1030}
1031