HardwareRenderer.java revision 44b2fe3fc114ee5f7273c6b0fee2cc999bf244a2
12d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy/*
22d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy * Copyright (C) 2010 The Android Open Source Project
32d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy *
42d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy * Licensed under the Apache License, Version 2.0 (the "License");
52d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy * you may not use this file except in compliance with the License.
62d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy * You may obtain a copy of the License at
72d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy *
82d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy *      http://www.apache.org/licenses/LICENSE-2.0
92d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy *
102d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy * Unless required by applicable law or agreed to in writing, software
112d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy * distributed under the License is distributed on an "AS IS" BASIS,
122d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy * See the License for the specific language governing permissions and
142d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy * limitations under the License.
152d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy */
162d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
172d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
182d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guypackage android.view;
192d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
20c68c913d357e2955d4bd7ca52829071e531c7825Dianne Hackbornimport android.content.ComponentCallbacks2;
217d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guyimport android.graphics.Paint;
227d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guyimport android.graphics.Rect;
23aa6c24c21c727a196451332448d4e3b11a80be69Romain Guyimport android.graphics.SurfaceTexture;
24407ec78b828173257b0c5dae221649a4ccd8b058Romain Guyimport android.opengl.GLUtils;
25717a25dc2a411edb548859cd6870363346c71b01Dianne Hackbornimport android.opengl.ManagedEGLContext;
26717a25dc2a411edb548859cd6870363346c71b01Dianne Hackbornimport android.os.Handler;
27717a25dc2a411edb548859cd6870363346c71b01Dianne Hackbornimport android.os.Looper;
2802ccac69fd1c0a03c24c5f3ace0ad4bed337b1fdRomain Guyimport android.os.SystemClock;
2902ccac69fd1c0a03c24c5f3ace0ad4bed337b1fdRomain Guyimport android.os.SystemProperties;
30e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guyimport android.util.Log;
318ff6b9ebeeb24a6161ec6098e6bfdf8790ee5695Romain Guyimport com.google.android.gles_jni.EGLImpl;
322d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
332d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guyimport javax.microedition.khronos.egl.EGL10;
342d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guyimport javax.microedition.khronos.egl.EGL11;
352d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guyimport javax.microedition.khronos.egl.EGLConfig;
362d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guyimport javax.microedition.khronos.egl.EGLContext;
372d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guyimport javax.microedition.khronos.egl.EGLDisplay;
382d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guyimport javax.microedition.khronos.egl.EGLSurface;
39e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guyimport javax.microedition.khronos.opengles.GL;
402d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
41a95826582773a194ed7fb66bc29c9b82fe9bb8d1Romain Guyimport java.io.File;
42a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guyimport java.io.PrintWriter;
43a95826582773a194ed7fb66bc29c9b82fe9bb8d1Romain Guy
44484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guyimport static javax.microedition.khronos.egl.EGL10.*;
45484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy
462d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy/**
47c6cc0f8c19d9eccf408a443fa2bf668af261dcd0Joe Onorato * Interface for rendering a ViewAncestor using hardware acceleration.
482d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy *
492d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy * @hide
502d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy */
5161c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guypublic abstract class HardwareRenderer {
524f6aff386045000c2c03b903c7109cb42092b7eaRomain Guy    static final String LOG_TAG = "HardwareRenderer";
53fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy
545233920a216302b4aa03b100c32e8b3efe33cbc6Romain Guy    /**
55a95826582773a194ed7fb66bc29c9b82fe9bb8d1Romain Guy     * Name of the file that holds the shaders cache.
56a95826582773a194ed7fb66bc29c9b82fe9bb8d1Romain Guy     */
57a95826582773a194ed7fb66bc29c9b82fe9bb8d1Romain Guy    private static final String CACHE_PATH_SHADERS = "com.android.opengl.shaders_cache";
58a95826582773a194ed7fb66bc29c9b82fe9bb8d1Romain Guy
59a95826582773a194ed7fb66bc29c9b82fe9bb8d1Romain Guy    /**
607d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy     * Turn on to only refresh the parts of the screen that need updating.
61069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy     * When turned on the property defined by {@link #RENDER_DIRTY_REGIONS_PROPERTY}
62069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy     * must also have the value "true".
637d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy     */
647d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    public static final boolean RENDER_DIRTY_REGIONS = true;
657d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy
667d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    /**
67069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy     * System property used to enable or disable dirty regions invalidation.
68069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy     * This property is only queried if {@link #RENDER_DIRTY_REGIONS} is true.
69069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy     * The default value of this property is assumed to be true.
70069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy     *
71069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy     * Possible values:
72069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy     * "true", to enable partial invalidates
73069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy     * "false", to disable partial invalidates
74069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy     */
754b8c4f886b3d57e6ffe1a4650487c67334674a40Romain Guy    static final String RENDER_DIRTY_REGIONS_PROPERTY = "debug.hwui.render_dirty_regions";
769ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy
779ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy    /**
789ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy     * System property used to enable or disable vsync.
799ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy     * The default value of this property is assumed to be false.
809ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy     *
819ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy     * Possible values:
829ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy     * "true", to disable vsync
839ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy     * "false", to enable vsync
849ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy     */
854b8c4f886b3d57e6ffe1a4650487c67334674a40Romain Guy    static final String DISABLE_VSYNC_PROPERTY = "debug.hwui.disable_vsync";
86069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy
87069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy    /**
88a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy     * System property used to enable or disable hardware rendering profiling.
89a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy     * The default value of this property is assumed to be false.
9009280606dc5dc1b8f12f9317cf6922772b7d10a7Chet Haase     *
91a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy     * When profiling is enabled, the adb shell dumpsys gfxinfo command will
92a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy     * output extra information about the time taken to execute by the last
93a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy     * frames.
94a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy     *
95a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy     * Possible values:
96a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy     * "true", to enable profiling
97a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy     * "false", to disable profiling
984b8c4f886b3d57e6ffe1a4650487c67334674a40Romain Guy     *
994b8c4f886b3d57e6ffe1a4650487c67334674a40Romain Guy     * @hide
100a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy     */
1014b8c4f886b3d57e6ffe1a4650487c67334674a40Romain Guy    public static final String PROFILE_PROPERTY = "debug.hwui.profile";
102a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy
103a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy    /**
10409280606dc5dc1b8f12f9317cf6922772b7d10a7Chet Haase     * System property used to specify the number of frames to be used
10509280606dc5dc1b8f12f9317cf6922772b7d10a7Chet Haase     * when doing hardware rendering profiling.
10609280606dc5dc1b8f12f9317cf6922772b7d10a7Chet Haase     * The default value of this property is #PROFILE_MAX_FRAMES.
10709280606dc5dc1b8f12f9317cf6922772b7d10a7Chet Haase     *
10809280606dc5dc1b8f12f9317cf6922772b7d10a7Chet Haase     * When profiling is enabled, the adb shell dumpsys gfxinfo command will
10909280606dc5dc1b8f12f9317cf6922772b7d10a7Chet Haase     * output extra information about the time taken to execute by the last
11009280606dc5dc1b8f12f9317cf6922772b7d10a7Chet Haase     * frames.
11109280606dc5dc1b8f12f9317cf6922772b7d10a7Chet Haase     *
11209280606dc5dc1b8f12f9317cf6922772b7d10a7Chet Haase     * Possible values:
11309280606dc5dc1b8f12f9317cf6922772b7d10a7Chet Haase     * "60", to set the limit of frames to 60
11409280606dc5dc1b8f12f9317cf6922772b7d10a7Chet Haase     */
1154b8c4f886b3d57e6ffe1a4650487c67334674a40Romain Guy    static final String PROFILE_MAXFRAMES_PROPERTY = "debug.hwui.profile.maxframes";
11609280606dc5dc1b8f12f9317cf6922772b7d10a7Chet Haase
11709280606dc5dc1b8f12f9317cf6922772b7d10a7Chet Haase    /**
118484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy     * System property used to debug EGL configuration choice.
119484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy     *
120484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy     * Possible values:
121484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy     * "choice", print the chosen configuration only
122484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy     * "all", print all possible configurations
123484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy     */
1244b8c4f886b3d57e6ffe1a4650487c67334674a40Romain Guy    static final String PRINT_CONFIG_PROPERTY = "debug.hwui.print_config";
125484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy
126484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy    /**
1277d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy     * Turn on to draw dirty regions every other frame.
128b04f7e9438e8f73081f9be3fda166098042263a5Romain Guy     *
129b04f7e9438e8f73081f9be3fda166098042263a5Romain Guy     * Possible values:
130b04f7e9438e8f73081f9be3fda166098042263a5Romain Guy     * "true", to enable dirty regions debugging
131b04f7e9438e8f73081f9be3fda166098042263a5Romain Guy     * "false", to disable dirty regions debugging
1324b8c4f886b3d57e6ffe1a4650487c67334674a40Romain Guy     *
1334b8c4f886b3d57e6ffe1a4650487c67334674a40Romain Guy     * @hide
1347d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy     */
1354b8c4f886b3d57e6ffe1a4650487c67334674a40Romain Guy    public static final String DEBUG_DIRTY_REGIONS_PROPERTY = "debug.hwui.show_dirty_regions";
1367d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy
1377d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    /**
1385233920a216302b4aa03b100c32e8b3efe33cbc6Romain Guy     * A process can set this flag to false to prevent the use of hardware
1395233920a216302b4aa03b100c32e8b3efe33cbc6Romain Guy     * rendering.
1405233920a216302b4aa03b100c32e8b3efe33cbc6Romain Guy     *
1415233920a216302b4aa03b100c32e8b3efe33cbc6Romain Guy     * @hide
1425233920a216302b4aa03b100c32e8b3efe33cbc6Romain Guy     */
1435233920a216302b4aa03b100c32e8b3efe33cbc6Romain Guy    public static boolean sRendererDisabled = false;
1445233920a216302b4aa03b100c32e8b3efe33cbc6Romain Guy
1455d927c2d8e832fcfcb0154c8741f896001141ef4Dianne Hackborn    /**
1465d927c2d8e832fcfcb0154c8741f896001141ef4Dianne Hackborn     * Further hardware renderer disabling for the system process.
1475d927c2d8e832fcfcb0154c8741f896001141ef4Dianne Hackborn     *
1485d927c2d8e832fcfcb0154c8741f896001141ef4Dianne Hackborn     * @hide
1495d927c2d8e832fcfcb0154c8741f896001141ef4Dianne Hackborn     */
1505d927c2d8e832fcfcb0154c8741f896001141ef4Dianne Hackborn    public static boolean sSystemRendererDisabled = false;
1515d927c2d8e832fcfcb0154c8741f896001141ef4Dianne Hackborn
152a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy    /**
153a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy     * Number of frames to profile.
154a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy     */
155a21f877434dd25a93869b8641e3c38618bf317a9Romain Guy    private static final int PROFILE_MAX_FRAMES = 128;
156a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy
157a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy    /**
158a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy     * Number of floats per profiled frame.
159a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy     */
160a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy    private static final int PROFILE_FRAME_DATA_COUNT = 3;
161a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy
1622d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    private boolean mEnabled;
1632d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    private boolean mRequested = true;
1642d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
1652d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    /**
16667f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy     * Invoke this method to disable hardware rendering in the current process.
1675233920a216302b4aa03b100c32e8b3efe33cbc6Romain Guy     *
1685233920a216302b4aa03b100c32e8b3efe33cbc6Romain Guy     * @hide
1695233920a216302b4aa03b100c32e8b3efe33cbc6Romain Guy     */
1705d927c2d8e832fcfcb0154c8741f896001141ef4Dianne Hackborn    public static void disable(boolean system) {
1715233920a216302b4aa03b100c32e8b3efe33cbc6Romain Guy        sRendererDisabled = true;
1725d927c2d8e832fcfcb0154c8741f896001141ef4Dianne Hackborn        if (system) {
1735d927c2d8e832fcfcb0154c8741f896001141ef4Dianne Hackborn            sSystemRendererDisabled = true;
1745d927c2d8e832fcfcb0154c8741f896001141ef4Dianne Hackborn        }
1755233920a216302b4aa03b100c32e8b3efe33cbc6Romain Guy    }
1765233920a216302b4aa03b100c32e8b3efe33cbc6Romain Guy
1775233920a216302b4aa03b100c32e8b3efe33cbc6Romain Guy    /**
17861c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy     * Indicates whether hardware acceleration is available under any form for
17961c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy     * the view hierarchy.
18061c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy     *
18161c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy     * @return True if the view hierarchy can potentially be hardware accelerated,
18261c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy     *         false otherwise
18361c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy     */
18461c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy    public static boolean isAvailable() {
18561c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        return GLES20Canvas.isAvailable();
18661c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy    }
18761c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy
18861c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy    /**
1892d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * Destroys the hardware rendering context.
1904caa4ed120a86e855d4d3b6b455c6fb9ca22e365Romain Guy     *
1914caa4ed120a86e855d4d3b6b455c6fb9ca22e365Romain Guy     * @param full If true, destroys all associated resources.
1922d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     */
1934caa4ed120a86e855d4d3b6b455c6fb9ca22e365Romain Guy    abstract void destroy(boolean full);
1942d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
1952d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    /**
1962d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * Initializes the hardware renderer for the specified surface.
1972d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     *
1982d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * @param holder The holder for the surface to hardware accelerate.
1992d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     *
2002d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * @return True if the initialization was successful, false otherwise.
2012d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     */
202648251710162cdaf7371012a1cbb79b9bc5bc0e4Dianne Hackborn    abstract boolean initialize(SurfaceHolder holder) throws Surface.OutOfResourcesException;
2032a83f001fdb189f945e82e81e717ba204824b112Romain Guy
2042a83f001fdb189f945e82e81e717ba204824b112Romain Guy    /**
2052a83f001fdb189f945e82e81e717ba204824b112Romain Guy     * Updates the hardware renderer for the specified surface.
2062a83f001fdb189f945e82e81e717ba204824b112Romain Guy     *
207cf15efba0792b052dca5baa350d9fb00e6a60667Romain Guy     * @param holder The holder for the surface to hardware accelerate
2082a83f001fdb189f945e82e81e717ba204824b112Romain Guy     */
209648251710162cdaf7371012a1cbb79b9bc5bc0e4Dianne Hackborn    abstract void updateSurface(SurfaceHolder holder) throws Surface.OutOfResourcesException;
2102d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
2112d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    /**
21231f2c2e94656530fbf6282803e62edb47e9a894dRomain Guy     * Destroys the layers used by the specified view hierarchy.
2136d7475d666baefaa3ba9f0dcee25238739454241Romain Guy     *
2146d7475d666baefaa3ba9f0dcee25238739454241Romain Guy     * @param view The root of the view hierarchy
2156d7475d666baefaa3ba9f0dcee25238739454241Romain Guy     */
2166d7475d666baefaa3ba9f0dcee25238739454241Romain Guy    abstract void destroyLayers(View view);
2176d7475d666baefaa3ba9f0dcee25238739454241Romain Guy
2186d7475d666baefaa3ba9f0dcee25238739454241Romain Guy    /**
21931f2c2e94656530fbf6282803e62edb47e9a894dRomain Guy     * Destroys all hardware rendering resources associated with the specified
22031f2c2e94656530fbf6282803e62edb47e9a894dRomain Guy     * view hierarchy.
22131f2c2e94656530fbf6282803e62edb47e9a894dRomain Guy     *
22231f2c2e94656530fbf6282803e62edb47e9a894dRomain Guy     * @param view The root of the view hierarchy
22331f2c2e94656530fbf6282803e62edb47e9a894dRomain Guy     */
22431f2c2e94656530fbf6282803e62edb47e9a894dRomain Guy    abstract void destroyHardwareResources(View view);
22531f2c2e94656530fbf6282803e62edb47e9a894dRomain Guy
22631f2c2e94656530fbf6282803e62edb47e9a894dRomain Guy    /**
227039857520b1a03a52051b966d87d587225bdfcc3Romain Guy     * This method should be invoked whenever the current hardware renderer
228cf15efba0792b052dca5baa350d9fb00e6a60667Romain Guy     * context should be reset.
229cf15efba0792b052dca5baa350d9fb00e6a60667Romain Guy     *
230cf15efba0792b052dca5baa350d9fb00e6a60667Romain Guy     * @param holder The holder for the surface to hardware accelerate
2317e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy     */
232cf15efba0792b052dca5baa350d9fb00e6a60667Romain Guy    abstract void invalidate(SurfaceHolder holder);
233039857520b1a03a52051b966d87d587225bdfcc3Romain Guy
234039857520b1a03a52051b966d87d587225bdfcc3Romain Guy    /**
235039857520b1a03a52051b966d87d587225bdfcc3Romain Guy     * This method should be invoked to ensure the hardware renderer is in
236039857520b1a03a52051b966d87d587225bdfcc3Romain Guy     * valid state (for instance, to ensure the correct EGL context is bound
237039857520b1a03a52051b966d87d587225bdfcc3Romain Guy     * to the current thread.)
238039857520b1a03a52051b966d87d587225bdfcc3Romain Guy     *
239039857520b1a03a52051b966d87d587225bdfcc3Romain Guy     * @return true if the renderer is now valid, false otherwise
240039857520b1a03a52051b966d87d587225bdfcc3Romain Guy     */
241039857520b1a03a52051b966d87d587225bdfcc3Romain Guy    abstract boolean validate();
2427e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy
2437e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy    /**
2441ac4765e959c79101f64b1279887ed469334c268Romain Guy     * This method ensures the hardware renderer is in a valid state
2451ac4765e959c79101f64b1279887ed469334c268Romain Guy     * before executing the specified action.
2461ac4765e959c79101f64b1279887ed469334c268Romain Guy     *
2471ac4765e959c79101f64b1279887ed469334c268Romain Guy     * This method will attempt to set a valid state even if the window
2481ac4765e959c79101f64b1279887ed469334c268Romain Guy     * the renderer is attached to was destroyed.
2491ac4765e959c79101f64b1279887ed469334c268Romain Guy     *
2501ac4765e959c79101f64b1279887ed469334c268Romain Guy     * @return true if the action was run
2511ac4765e959c79101f64b1279887ed469334c268Romain Guy     */
2521ac4765e959c79101f64b1279887ed469334c268Romain Guy    abstract boolean safelyRun(Runnable action);
2531ac4765e959c79101f64b1279887ed469334c268Romain Guy
2541ac4765e959c79101f64b1279887ed469334c268Romain Guy    /**
2557e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy     * Setup the hardware renderer for drawing. This is called whenever the
2567e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy     * size of the target surface changes or when the surface is first created.
2572d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     *
2582d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * @param width Width of the drawing surface.
2592d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * @param height Height of the drawing surface.
2602d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     */
261fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    abstract void setup(int width, int height);
2622d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
263069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy    /**
26440e0383dce630ed9b2b1aa0e497709b89dfab6efChet Haase     * Gets the current width of the surface. This is the width that the surface
26540e0383dce630ed9b2b1aa0e497709b89dfab6efChet Haase     * was last set to in a call to {@link #setup(int, int)}.
26640e0383dce630ed9b2b1aa0e497709b89dfab6efChet Haase     *
26740e0383dce630ed9b2b1aa0e497709b89dfab6efChet Haase     * @return the current width of the surface
26840e0383dce630ed9b2b1aa0e497709b89dfab6efChet Haase     */
26940e0383dce630ed9b2b1aa0e497709b89dfab6efChet Haase    abstract int getWidth();
27040e0383dce630ed9b2b1aa0e497709b89dfab6efChet Haase
27140e0383dce630ed9b2b1aa0e497709b89dfab6efChet Haase    /**
27240e0383dce630ed9b2b1aa0e497709b89dfab6efChet Haase     * Gets the current height of the surface. This is the height that the surface
27340e0383dce630ed9b2b1aa0e497709b89dfab6efChet Haase     * was last set to in a call to {@link #setup(int, int)}.
27440e0383dce630ed9b2b1aa0e497709b89dfab6efChet Haase     *
27540e0383dce630ed9b2b1aa0e497709b89dfab6efChet Haase     * @return the current width of the surface
27640e0383dce630ed9b2b1aa0e497709b89dfab6efChet Haase     */
27740e0383dce630ed9b2b1aa0e497709b89dfab6efChet Haase    abstract int getHeight();
27840e0383dce630ed9b2b1aa0e497709b89dfab6efChet Haase
27940e0383dce630ed9b2b1aa0e497709b89dfab6efChet Haase    /**
28008837c246c9c27902c59b41c8661c2f27a4aa2bcChet Haase     * Gets the current canvas associated with this HardwareRenderer.
28108837c246c9c27902c59b41c8661c2f27a4aa2bcChet Haase     *
28208837c246c9c27902c59b41c8661c2f27a4aa2bcChet Haase     * @return the current HardwareCanvas
28308837c246c9c27902c59b41c8661c2f27a4aa2bcChet Haase     */
28408837c246c9c27902c59b41c8661c2f27a4aa2bcChet Haase    abstract HardwareCanvas getCanvas();
28508837c246c9c27902c59b41c8661c2f27a4aa2bcChet Haase
28608837c246c9c27902c59b41c8661c2f27a4aa2bcChet Haase    /**
287a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy     * Outputs extra debugging information in the specified file descriptor.
288a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy     * @param pw
289a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy     */
290a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy    abstract void dumpGfxInfo(PrintWriter pw);
291a3fabff98590d26f0c362cb09dc378fece66215cMichael Jurka
292a3fabff98590d26f0c362cb09dc378fece66215cMichael Jurka    /**
293a3fabff98590d26f0c362cb09dc378fece66215cMichael Jurka     * Outputs the total number of frames rendered (used for fps calculations)
294a3fabff98590d26f0c362cb09dc378fece66215cMichael Jurka     *
295a3fabff98590d26f0c362cb09dc378fece66215cMichael Jurka     * @return the number of frames rendered
296a3fabff98590d26f0c362cb09dc378fece66215cMichael Jurka     */
297a3fabff98590d26f0c362cb09dc378fece66215cMichael Jurka    abstract long getFrameCount();
298a3fabff98590d26f0c362cb09dc378fece66215cMichael Jurka
299a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy    /**
300a95826582773a194ed7fb66bc29c9b82fe9bb8d1Romain Guy     * Sets the directory to use as a persistent storage for hardware rendering
301a95826582773a194ed7fb66bc29c9b82fe9bb8d1Romain Guy     * resources.
302a95826582773a194ed7fb66bc29c9b82fe9bb8d1Romain Guy     *
303a95826582773a194ed7fb66bc29c9b82fe9bb8d1Romain Guy     * @param cacheDir A directory the current process can write to
304a95826582773a194ed7fb66bc29c9b82fe9bb8d1Romain Guy     */
305a95826582773a194ed7fb66bc29c9b82fe9bb8d1Romain Guy    public static void setupDiskCache(File cacheDir) {
306a95826582773a194ed7fb66bc29c9b82fe9bb8d1Romain Guy        nSetupShadersDiskCache(new File(cacheDir, CACHE_PATH_SHADERS).getAbsolutePath());
307a95826582773a194ed7fb66bc29c9b82fe9bb8d1Romain Guy    }
308a95826582773a194ed7fb66bc29c9b82fe9bb8d1Romain Guy
309a95826582773a194ed7fb66bc29c9b82fe9bb8d1Romain Guy    private static native void nSetupShadersDiskCache(String cacheFile);
310a95826582773a194ed7fb66bc29c9b82fe9bb8d1Romain Guy
311a95826582773a194ed7fb66bc29c9b82fe9bb8d1Romain Guy    /**
312b335fad4705348ff78d764fb4be53dcbe6b67abeJamie Gennis     * Notifies EGL that the frame is about to be rendered.
3137687882800f49e3fc3a14f1d7540412f77d6bd4dRomain Guy     * @param size
314b335fad4705348ff78d764fb4be53dcbe6b67abeJamie Gennis     */
3157687882800f49e3fc3a14f1d7540412f77d6bd4dRomain Guy    private static void beginFrame(int[] size) {
3167687882800f49e3fc3a14f1d7540412f77d6bd4dRomain Guy        nBeginFrame(size);
317b335fad4705348ff78d764fb4be53dcbe6b67abeJamie Gennis    }
318b335fad4705348ff78d764fb4be53dcbe6b67abeJamie Gennis
3197687882800f49e3fc3a14f1d7540412f77d6bd4dRomain Guy    private static native void nBeginFrame(int[] size);
320b335fad4705348ff78d764fb4be53dcbe6b67abeJamie Gennis
321b335fad4705348ff78d764fb4be53dcbe6b67abeJamie Gennis    /**
322244ada1d35419b7be9de0fc833bb03955b725ffaRomain Guy     * Preserves the back buffer of the current surface after a buffer swap.
323244ada1d35419b7be9de0fc833bb03955b725ffaRomain Guy     * Calling this method sets the EGL_SWAP_BEHAVIOR attribute of the current
324244ada1d35419b7be9de0fc833bb03955b725ffaRomain Guy     * surface to EGL_BUFFER_PRESERVED. Calling this method requires an EGL
325244ada1d35419b7be9de0fc833bb03955b725ffaRomain Guy     * config that supports EGL_SWAP_BEHAVIOR_PRESERVED_BIT.
326244ada1d35419b7be9de0fc833bb03955b725ffaRomain Guy     *
327244ada1d35419b7be9de0fc833bb03955b725ffaRomain Guy     * @return True if the swap behavior was successfully changed,
328244ada1d35419b7be9de0fc833bb03955b725ffaRomain Guy     *         false otherwise.
329244ada1d35419b7be9de0fc833bb03955b725ffaRomain Guy     */
330244ada1d35419b7be9de0fc833bb03955b725ffaRomain Guy    static boolean preserveBackBuffer() {
331244ada1d35419b7be9de0fc833bb03955b725ffaRomain Guy        return nPreserveBackBuffer();
332244ada1d35419b7be9de0fc833bb03955b725ffaRomain Guy    }
333244ada1d35419b7be9de0fc833bb03955b725ffaRomain Guy
334244ada1d35419b7be9de0fc833bb03955b725ffaRomain Guy    private static native boolean nPreserveBackBuffer();
335244ada1d35419b7be9de0fc833bb03955b725ffaRomain Guy
336244ada1d35419b7be9de0fc833bb03955b725ffaRomain Guy    /**
337244ada1d35419b7be9de0fc833bb03955b725ffaRomain Guy     * Indicates whether the current surface preserves its back buffer
338244ada1d35419b7be9de0fc833bb03955b725ffaRomain Guy     * after a buffer swap.
339244ada1d35419b7be9de0fc833bb03955b725ffaRomain Guy     *
340244ada1d35419b7be9de0fc833bb03955b725ffaRomain Guy     * @return True, if the surface's EGL_SWAP_BEHAVIOR is EGL_BUFFER_PRESERVED,
341244ada1d35419b7be9de0fc833bb03955b725ffaRomain Guy     *         false otherwise
342244ada1d35419b7be9de0fc833bb03955b725ffaRomain Guy     */
343244ada1d35419b7be9de0fc833bb03955b725ffaRomain Guy    static boolean isBackBufferPreserved() {
344244ada1d35419b7be9de0fc833bb03955b725ffaRomain Guy        return nIsBackBufferPreserved();
345244ada1d35419b7be9de0fc833bb03955b725ffaRomain Guy    }
346244ada1d35419b7be9de0fc833bb03955b725ffaRomain Guy
347244ada1d35419b7be9de0fc833bb03955b725ffaRomain Guy    private static native boolean nIsBackBufferPreserved();
348244ada1d35419b7be9de0fc833bb03955b725ffaRomain Guy
349244ada1d35419b7be9de0fc833bb03955b725ffaRomain Guy    /**
350244ada1d35419b7be9de0fc833bb03955b725ffaRomain Guy     * Disables v-sync. For performance testing only.
351244ada1d35419b7be9de0fc833bb03955b725ffaRomain Guy     */
352244ada1d35419b7be9de0fc833bb03955b725ffaRomain Guy    static void disableVsync() {
353244ada1d35419b7be9de0fc833bb03955b725ffaRomain Guy        nDisableVsync();
354244ada1d35419b7be9de0fc833bb03955b725ffaRomain Guy    }
355244ada1d35419b7be9de0fc833bb03955b725ffaRomain Guy
356244ada1d35419b7be9de0fc833bb03955b725ffaRomain Guy    private static native void nDisableVsync();
357244ada1d35419b7be9de0fc833bb03955b725ffaRomain Guy
358244ada1d35419b7be9de0fc833bb03955b725ffaRomain Guy    /**
359069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy     * Interface used to receive callbacks whenever a view is drawn by
360069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy     * a hardware renderer instance.
361069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy     */
3620f761d6b8f5d5a607c87dbcdca6fe0ec7911970eDianne Hackborn    interface HardwareDrawCallbacks {
363069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy        /**
364069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy         * Invoked before a view is drawn by a hardware renderer.
365069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy         *
366069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy         * @param canvas The Canvas used to render the view.
367069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy         */
3687d70fbf0b5672bada8b25f065bc292796c3d4812Romain Guy        void onHardwarePreDraw(HardwareCanvas canvas);
369069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy
370069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy        /**
371069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy         * Invoked after a view is drawn by a hardware renderer.
372069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy         *
373069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy         * @param canvas The Canvas used to render the view.
374069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy         */
3757d70fbf0b5672bada8b25f065bc292796c3d4812Romain Guy        void onHardwarePostDraw(HardwareCanvas canvas);
3760f761d6b8f5d5a607c87dbcdca6fe0ec7911970eDianne Hackborn    }
3770f761d6b8f5d5a607c87dbcdca6fe0ec7911970eDianne Hackborn
3782d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    /**
3792d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * Draws the specified view.
3807d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy     *
3812d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * @param view The view to draw.
3822d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * @param attachInfo AttachInfo tied to the specified view.
3837d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy     * @param callbacks Callbacks invoked when drawing happens.
3847d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy     * @param dirty The dirty rectangle to update, can be null.
38550d133e290468fd149b5c03e46549afca2ee05f8Romain Guy     *
38650d133e290468fd149b5c03e46549afca2ee05f8Romain Guy     * @return true if the dirty rect was ignored, false otherwise
3872d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     */
38850d133e290468fd149b5c03e46549afca2ee05f8Romain Guy    abstract boolean draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks,
3897d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy            Rect dirty);
3902d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
3912d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    /**
39253ca03d9a3a6a95286302802173c4820b16328ceRomain Guy     * Creates a new display list that can be used to record batches of
39353ca03d9a3a6a95286302802173c4820b16328ceRomain Guy     * drawing operations.
394b051e895ccb696604349c6c5efe7c4747e1d1ab6Romain Guy     *
39513631f3da855f200a151e7837ed9f6b079622b58Romain Guy     * @param name The name of the display list, used for debugging purpose.
39613631f3da855f200a151e7837ed9f6b079622b58Romain Guy     *             May be null
39713631f3da855f200a151e7837ed9f6b079622b58Romain Guy     *
39853ca03d9a3a6a95286302802173c4820b16328ceRomain Guy     * @return A new display list.
399b051e895ccb696604349c6c5efe7c4747e1d1ab6Romain Guy     */
40013631f3da855f200a151e7837ed9f6b079622b58Romain Guy    public abstract DisplayList createDisplayList(String name);
401b051e895ccb696604349c6c5efe7c4747e1d1ab6Romain Guy
402b051e895ccb696604349c6c5efe7c4747e1d1ab6Romain Guy    /**
403aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy     * Creates a new hardware layer. A hardware layer built by calling this
404aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy     * method will be treated as a texture layer, instead of as a render target.
405aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy     *
406a9489274d67b540804aafb587a226f7c2ae4464dRomain Guy     * @param isOpaque Whether the layer should be opaque or not
407a9489274d67b540804aafb587a226f7c2ae4464dRomain Guy     *
408aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy     * @return A hardware layer
4092af3524beb75150d347accc925022daa53b4a789Jamie Gennis     */
410a9489274d67b540804aafb587a226f7c2ae4464dRomain Guy    abstract HardwareLayer createHardwareLayer(boolean isOpaque);
4112af3524beb75150d347accc925022daa53b4a789Jamie Gennis
412aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy    /**
4136c319ca1275c8db892c39b48fc54864c949f9171Romain Guy     * Creates a new hardware layer.
4146c319ca1275c8db892c39b48fc54864c949f9171Romain Guy     *
4156c319ca1275c8db892c39b48fc54864c949f9171Romain Guy     * @param width The minimum width of the layer
4166c319ca1275c8db892c39b48fc54864c949f9171Romain Guy     * @param height The minimum height of the layer
4176c319ca1275c8db892c39b48fc54864c949f9171Romain Guy     * @param isOpaque Whether the layer should be opaque or not
4186c319ca1275c8db892c39b48fc54864c949f9171Romain Guy     *
4196c319ca1275c8db892c39b48fc54864c949f9171Romain Guy     * @return A hardware layer
4206c319ca1275c8db892c39b48fc54864c949f9171Romain Guy     */
4216c319ca1275c8db892c39b48fc54864c949f9171Romain Guy    abstract HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque);
422aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy
423aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy    /**
424aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy     * Creates a new {@link SurfaceTexture} that can be used to render into the
425aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy     * specified hardware layer.
426aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy     *
427aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy     *
428aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy     * @param layer The layer to render into using a {@link android.graphics.SurfaceTexture}
429aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy     *
430aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy     * @return A {@link SurfaceTexture}
431aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy     */
432e5e0c50f7dfaccc220725c5595080e921ffda1e4Romain Guy    abstract SurfaceTexture createSurfaceTexture(HardwareLayer layer);
433aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy
434aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy    /**
4352af3524beb75150d347accc925022daa53b4a789Jamie Gennis     * Sets the {@link android.graphics.SurfaceTexture} that will be used to
4362af3524beb75150d347accc925022daa53b4a789Jamie Gennis     * render into the specified hardware layer.
4372af3524beb75150d347accc925022daa53b4a789Jamie Gennis     *
4382af3524beb75150d347accc925022daa53b4a789Jamie Gennis     * @param layer The layer to render into using a {@link android.graphics.SurfaceTexture}
4392af3524beb75150d347accc925022daa53b4a789Jamie Gennis     * @param surfaceTexture The {@link android.graphics.SurfaceTexture} to use for the layer
4402af3524beb75150d347accc925022daa53b4a789Jamie Gennis     */
4412af3524beb75150d347accc925022daa53b4a789Jamie Gennis    abstract void setSurfaceTexture(HardwareLayer layer, SurfaceTexture surfaceTexture);
4422af3524beb75150d347accc925022daa53b4a789Jamie Gennis
4432af3524beb75150d347accc925022daa53b4a789Jamie Gennis    /**
444ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy     * Detaches the specified functor from the current functor execution queue.
445ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy     *
446ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy     * @param functor The native functor to remove from the execution queue.
447ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy     *
448ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy     * @see HardwareCanvas#callDrawGLFunction(int)
449ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy     * @see #attachFunctor(android.view.View.AttachInfo, int)
450ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy     */
451ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy    abstract void detachFunctor(int functor);
452ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy
453ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy    /**
454ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy     * Schedules the specified functor in the functors execution queue.
455ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy     *
456ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy     * @param attachInfo AttachInfo tied to this renderer.
457ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy     * @param functor The native functor to insert in the execution queue.
458ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy     *
459ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy     * @see HardwareCanvas#callDrawGLFunction(int)
46041ee465734d0006797a8fd36e88976c1e85d161cChris Craik     * @see #detachFunctor(int)
46141ee465734d0006797a8fd36e88976c1e85d161cChris Craik     *
46241ee465734d0006797a8fd36e88976c1e85d161cChris Craik     * @return true if the functor was attached successfully
463ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy     */
46441ee465734d0006797a8fd36e88976c1e85d161cChris Craik    abstract boolean attachFunctor(View.AttachInfo attachInfo, int functor);
465ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy
466ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy    /**
4672d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * Initializes the hardware renderer for the specified surface and setup the
468c6cc0f8c19d9eccf408a443fa2bf668af261dcd0Joe Onorato     * renderer for drawing, if needed. This is invoked when the ViewAncestor has
4692d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * potentially lost the hardware renderer. The hardware renderer should be
4702d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * reinitialized and setup when the render {@link #isRequested()} and
4712d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * {@link #isEnabled()}.
47244d79747b5e434e8f43928b5548442c65e40e5c3Romain Guy     *
4732d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * @param width The width of the drawing surface.
4742d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * @param height The height of the drawing surface.
47544d79747b5e434e8f43928b5548442c65e40e5c3Romain Guy     * @param holder The target surface
4762d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     */
47744d79747b5e434e8f43928b5548442c65e40e5c3Romain Guy    void initializeIfNeeded(int width, int height, SurfaceHolder holder)
47844d79747b5e434e8f43928b5548442c65e40e5c3Romain Guy            throws Surface.OutOfResourcesException {
4792d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        if (isRequested()) {
4802d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy            // We lost the gl context, so recreate it.
4812d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy            if (!isEnabled()) {
4822d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy                if (initialize(holder)) {
483fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy                    setup(width, height);
4842d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy                }
4852d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy            }
4862d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        }
4872d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    }
4882d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
4892d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    /**
4902d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * Creates a hardware renderer using OpenGL.
4912d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     *
4922d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * @param glVersion The version of OpenGL to use (1 for OpenGL 1, 11 for OpenGL 1.1, etc.)
493e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy     * @param translucent True if the surface is translucent, false otherwise
4942d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     *
4952d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * @return A hardware renderer backed by OpenGL.
4962d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     */
497e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    static HardwareRenderer createGlRenderer(int glVersion, boolean translucent) {
4982d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        switch (glVersion) {
499e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            case 2:
500163935113919a184122b8b3bd672ef08c8df65dcRomain Guy                return Gl20Renderer.create(translucent);
5012d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        }
5022d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        throw new IllegalArgumentException("Unknown GL version: " + glVersion);
5032d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    }
5042d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
5052d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    /**
506bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy     * Invoke this method when the system is running out of memory. This
507bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy     * method will attempt to recover as much memory as possible, based on
508bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy     * the specified hint.
509bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy     *
510bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy     * @param level Hint about the amount of memory that should be trimmed,
511bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy     *              see {@link android.content.ComponentCallbacks}
512bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy     */
513bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy    static void trimMemory(int level) {
51419f86e831ee0629b24385b0bb51d27ff91961dd2Romain Guy        startTrimMemory(level);
51519f86e831ee0629b24385b0bb51d27ff91961dd2Romain Guy        endTrimMemory();
51619f86e831ee0629b24385b0bb51d27ff91961dd2Romain Guy    }
51719f86e831ee0629b24385b0bb51d27ff91961dd2Romain Guy
51819f86e831ee0629b24385b0bb51d27ff91961dd2Romain Guy    /**
51919f86e831ee0629b24385b0bb51d27ff91961dd2Romain Guy     * Starts the process of trimming memory. Usually this call will setup
52019f86e831ee0629b24385b0bb51d27ff91961dd2Romain Guy     * hardware rendering context and reclaim memory.Extra cleanup might
52119f86e831ee0629b24385b0bb51d27ff91961dd2Romain Guy     * be required by calling {@link #endTrimMemory()}.
52219f86e831ee0629b24385b0bb51d27ff91961dd2Romain Guy     *
52319f86e831ee0629b24385b0bb51d27ff91961dd2Romain Guy     * @param level Hint about the amount of memory that should be trimmed,
52419f86e831ee0629b24385b0bb51d27ff91961dd2Romain Guy     *              see {@link android.content.ComponentCallbacks}
52519f86e831ee0629b24385b0bb51d27ff91961dd2Romain Guy     */
52619f86e831ee0629b24385b0bb51d27ff91961dd2Romain Guy    static void startTrimMemory(int level) {
52719f86e831ee0629b24385b0bb51d27ff91961dd2Romain Guy        Gl20Renderer.startTrimMemory(level);
52819f86e831ee0629b24385b0bb51d27ff91961dd2Romain Guy    }
52919f86e831ee0629b24385b0bb51d27ff91961dd2Romain Guy
53019f86e831ee0629b24385b0bb51d27ff91961dd2Romain Guy    /**
53119f86e831ee0629b24385b0bb51d27ff91961dd2Romain Guy     * Finishes the process of trimming memory. This method will usually
53219f86e831ee0629b24385b0bb51d27ff91961dd2Romain Guy     * cleanup special resources used by the memory trimming process.
53319f86e831ee0629b24385b0bb51d27ff91961dd2Romain Guy     */
53419f86e831ee0629b24385b0bb51d27ff91961dd2Romain Guy    static void endTrimMemory() {
53519f86e831ee0629b24385b0bb51d27ff91961dd2Romain Guy        Gl20Renderer.endTrimMemory();
536bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy    }
537bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy
538bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy    /**
5392d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * Indicates whether hardware acceleration is currently enabled.
5402d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     *
5412d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * @return True if hardware acceleration is in use, false otherwise.
5422d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     */
5432d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    boolean isEnabled() {
5442d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        return mEnabled;
5452d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    }
5462d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
5472d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    /**
5482d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * Indicates whether hardware acceleration is currently enabled.
5492d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     *
5502d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * @param enabled True if the hardware renderer is in use, false otherwise.
5512d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     */
5522d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    void setEnabled(boolean enabled) {
5532d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        mEnabled = enabled;
5542d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    }
5552d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
5562d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    /**
5572d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * Indicates whether hardware acceleration is currently request but not
5582d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * necessarily enabled yet.
5592d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     *
5602d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * @return True if requested, false otherwise.
5612d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     */
5622d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    boolean isRequested() {
5632d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        return mRequested;
5642d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    }
5652d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
5662d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    /**
5679745fae73b584f3e9a9c304098ed9b11f506e93bRomain Guy     * Indicates whether hardware acceleration is currently requested but not
5682d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * necessarily enabled yet.
5692d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     *
5702d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * @return True to request hardware acceleration, false otherwise.
5712d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     */
5722d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    void setRequested(boolean requested) {
5732d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        mRequested = requested;
5742d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    }
5752d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
5762d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    @SuppressWarnings({"deprecation"})
577e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy    static abstract class GlRenderer extends HardwareRenderer {
578aaceeb0c5be11121a81e44b9633c06fc5c0fcd4dRomain Guy        // These values are not exposed in our EGL APIs
579e91a9c7ab075c43e983fdeb9af80447caa501337Romain Guy        static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
580e91a9c7ab075c43e983fdeb9af80447caa501337Romain Guy        static final int EGL_OPENGL_ES2_BIT = 4;
5817e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy        static final int EGL_SURFACE_TYPE = 0x3033;
5827e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy        static final int EGL_SWAP_BEHAVIOR_PRESERVED_BIT = 0x0400;
583e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
58416260e73f6c1c9dc94acf0d328a3c564426b8711Romain Guy        static final int SURFACE_STATE_ERROR = 0;
58516260e73f6c1c9dc94acf0d328a3c564426b8711Romain Guy        static final int SURFACE_STATE_SUCCESS = 1;
58616260e73f6c1c9dc94acf0d328a3c564426b8711Romain Guy        static final int SURFACE_STATE_UPDATED = 2;
5878f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy
58865924a3e56c2e7ac863f8e25e9f9a58b9db7d513Chris Craik        static final int FUNCTOR_PROCESS_DELAY = 4;
5898f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy
590fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        static EGL10 sEgl;
591fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        static EGLDisplay sEglDisplay;
592fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        static EGLConfig sEglConfig;
593566b3efb25299d2a9c8ae827522802bad965426aRomain Guy        static final Object[] sEglLock = new Object[0];
59440e0383dce630ed9b2b1aa0e497709b89dfab6efChet Haase        int mWidth = -1, mHeight = -1;
595e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
5965d6999e1ca457948e06792ea6259ffa947c9fa81Romain Guy        static final ThreadLocal<ManagedEGLContext> sEglContextStorage
5975d6999e1ca457948e06792ea6259ffa947c9fa81Romain Guy                = new ThreadLocal<ManagedEGLContext>();
598566b3efb25299d2a9c8ae827522802bad965426aRomain Guy
599566b3efb25299d2a9c8ae827522802bad965426aRomain Guy        EGLContext mEglContext;
600566b3efb25299d2a9c8ae827522802bad965426aRomain Guy        Thread mEglThread;
601fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy
602fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        EGLSurface mEglSurface;
603fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy
604e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        GL mGl;
60567f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy        HardwareCanvas mCanvas;
606a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy
607a3fabff98590d26f0c362cb09dc378fece66215cMichael Jurka        long mFrameCount;
6087d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy        Paint mDebugPaint;
6097d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy
6107e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy        static boolean sDirtyRegions;
6117e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy        static final boolean sDirtyRegionsRequested;
6127e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy        static {
6137e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy            String dirtyProperty = SystemProperties.get(RENDER_DIRTY_REGIONS_PROPERTY, "true");
6147e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy            //noinspection PointlessBooleanExpression,ConstantConditions
6157e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy            sDirtyRegions = RENDER_DIRTY_REGIONS && "true".equalsIgnoreCase(dirtyProperty);
6167e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy            sDirtyRegionsRequested = sDirtyRegions;
6177e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy        }
6187e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy
6197e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy        boolean mDirtyRegionsEnabled;
6209477c6e6581ce97976250951f33e1297604ac777Romain Guy        boolean mUpdateDirtyRegions;
6219477c6e6581ce97976250951f33e1297604ac777Romain Guy
6229ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy        final boolean mVsyncDisabled;
6232d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
624a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy        final boolean mProfileEnabled;
625a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy        final float[] mProfileData;
626a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy        int mProfileCurrentFrame = -PROFILE_FRAME_DATA_COUNT;
627b04f7e9438e8f73081f9be3fda166098042263a5Romain Guy
628b04f7e9438e8f73081f9be3fda166098042263a5Romain Guy        final boolean mDebugDirtyRegions;
629a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy
630e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        final int mGlVersion;
631e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        final boolean mTranslucent;
6322d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
633fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        private boolean mDestroyed;
634566b3efb25299d2a9c8ae827522802bad965426aRomain Guy
635cabfcc1364eb7e4de0b15b3574fba45027b45cfcRomain Guy        private final Rect mRedrawClip = new Rect();
6368f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy
6377687882800f49e3fc3a14f1d7540412f77d6bd4dRomain Guy        private final int[] mSurfaceSize = new int[2];
6388f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy        private final FunctorsRunnable mFunctorsRunnable = new FunctorsRunnable();
639fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy
640e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        GlRenderer(int glVersion, boolean translucent) {
641e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            mGlVersion = glVersion;
642e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            mTranslucent = translucent;
643b04f7e9438e8f73081f9be3fda166098042263a5Romain Guy
644b04f7e9438e8f73081f9be3fda166098042263a5Romain Guy            String property;
6459ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy
646b04f7e9438e8f73081f9be3fda166098042263a5Romain Guy            property = SystemProperties.get(DISABLE_VSYNC_PROPERTY, "false");
647b04f7e9438e8f73081f9be3fda166098042263a5Romain Guy            mVsyncDisabled = "true".equalsIgnoreCase(property);
6489ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy            if (mVsyncDisabled) {
6499ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy                Log.d(LOG_TAG, "Disabling v-sync");
6509ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy            }
651a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy
65213b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy            property = SystemProperties.get(PROFILE_PROPERTY, "false");
65313b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy            mProfileEnabled = "true".equalsIgnoreCase(property);
65413b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy            if (mProfileEnabled) {
65513b907353f18215b52b5ceda24bbf520d91d72a1Romain Guy                Log.d(LOG_TAG, "Profiling hardware renderer");
656a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy            }
657a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy
658a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy            if (mProfileEnabled) {
65909280606dc5dc1b8f12f9317cf6922772b7d10a7Chet Haase                property = SystemProperties.get(PROFILE_MAXFRAMES_PROPERTY,
66009280606dc5dc1b8f12f9317cf6922772b7d10a7Chet Haase                        Integer.toString(PROFILE_MAX_FRAMES));
66109280606dc5dc1b8f12f9317cf6922772b7d10a7Chet Haase                int maxProfileFrames = Integer.valueOf(property);
66209280606dc5dc1b8f12f9317cf6922772b7d10a7Chet Haase                mProfileData = new float[maxProfileFrames * PROFILE_FRAME_DATA_COUNT];
66309280606dc5dc1b8f12f9317cf6922772b7d10a7Chet Haase                for (int i = 0; i < mProfileData.length; i += PROFILE_FRAME_DATA_COUNT) {
66409280606dc5dc1b8f12f9317cf6922772b7d10a7Chet Haase                    mProfileData[i] = mProfileData[i + 1] = mProfileData[i + 2] = -1;
66509280606dc5dc1b8f12f9317cf6922772b7d10a7Chet Haase                }
666a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy            } else {
667a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy                mProfileData = null;
668a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy            }
669b04f7e9438e8f73081f9be3fda166098042263a5Romain Guy
670b04f7e9438e8f73081f9be3fda166098042263a5Romain Guy            property = SystemProperties.get(DEBUG_DIRTY_REGIONS_PROPERTY, "false");
671b04f7e9438e8f73081f9be3fda166098042263a5Romain Guy            mDebugDirtyRegions = "true".equalsIgnoreCase(property);
672b04f7e9438e8f73081f9be3fda166098042263a5Romain Guy            if (mDebugDirtyRegions) {
673b04f7e9438e8f73081f9be3fda166098042263a5Romain Guy                Log.d(LOG_TAG, "Debugging dirty regions");
674b04f7e9438e8f73081f9be3fda166098042263a5Romain Guy            }
675a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy        }
676a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy
677a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy        @Override
678a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy        void dumpGfxInfo(PrintWriter pw) {
679a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy            if (mProfileEnabled) {
680a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy                pw.printf("\n\tDraw\tProcess\tExecute\n");
681a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy                for (int i = 0; i < mProfileData.length; i += PROFILE_FRAME_DATA_COUNT) {
68209280606dc5dc1b8f12f9317cf6922772b7d10a7Chet Haase                    if (mProfileData[i] < 0) {
68309280606dc5dc1b8f12f9317cf6922772b7d10a7Chet Haase                        break;
68409280606dc5dc1b8f12f9317cf6922772b7d10a7Chet Haase                    }
685a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy                    pw.printf("\t%3.2f\t%3.2f\t%3.2f\n", mProfileData[i], mProfileData[i + 1],
686a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy                            mProfileData[i + 2]);
68709280606dc5dc1b8f12f9317cf6922772b7d10a7Chet Haase                    mProfileData[i] = mProfileData[i + 1] = mProfileData[i + 2] = -1;
688a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy                }
68909280606dc5dc1b8f12f9317cf6922772b7d10a7Chet Haase                mProfileCurrentFrame = mProfileData.length;
690a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy            }
6912d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        }
6922d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
693a3fabff98590d26f0c362cb09dc378fece66215cMichael Jurka        @Override
694a3fabff98590d26f0c362cb09dc378fece66215cMichael Jurka        long getFrameCount() {
695a3fabff98590d26f0c362cb09dc378fece66215cMichael Jurka            return mFrameCount;
696a3fabff98590d26f0c362cb09dc378fece66215cMichael Jurka        }
697a3fabff98590d26f0c362cb09dc378fece66215cMichael Jurka
698e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        /**
69902ccac69fd1c0a03c24c5f3ace0ad4bed337b1fdRomain Guy         * Indicates whether this renderer instance can track and update dirty regions.
70002ccac69fd1c0a03c24c5f3ace0ad4bed337b1fdRomain Guy         */
70102ccac69fd1c0a03c24c5f3ace0ad4bed337b1fdRomain Guy        boolean hasDirtyRegions() {
7027e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy            return mDirtyRegionsEnabled;
70302ccac69fd1c0a03c24c5f3ace0ad4bed337b1fdRomain Guy        }
70402ccac69fd1c0a03c24c5f3ace0ad4bed337b1fdRomain Guy
70502ccac69fd1c0a03c24c5f3ace0ad4bed337b1fdRomain Guy        /**
7064caa4ed120a86e855d4d3b6b455c6fb9ca22e365Romain Guy         * Checks for OpenGL errors. If an error has occured, {@link #destroy(boolean)}
707e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy         * is invoked and the requested flag is turned off. The error code is
708e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy         * also logged as a warning.
709e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy         */
710b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy        void checkEglErrors() {
711e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            if (isEnabled()) {
712fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy                int error = sEgl.eglGetError();
713484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                if (error != EGL_SUCCESS) {
714e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                    // something bad has happened revert to
715e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                    // normal rendering.
716407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy                    Log.w(LOG_TAG, "EGL error: " + GLUtils.getEGLErrorString(error));
717eca9b1f53c2c291cbfb89b5f3cc45db7bdca6c7dRomain Guy                    fallback(error != EGL11.EGL_CONTEXT_LOST);
718e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                }
7192d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy            }
7202d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        }
72167f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy
7229745fae73b584f3e9a9c304098ed9b11f506e93bRomain Guy        private void fallback(boolean fallback) {
7239745fae73b584f3e9a9c304098ed9b11f506e93bRomain Guy            destroy(true);
7249745fae73b584f3e9a9c304098ed9b11f506e93bRomain Guy            if (fallback) {
7259745fae73b584f3e9a9c304098ed9b11f506e93bRomain Guy                // we'll try again if it was context lost
7269745fae73b584f3e9a9c304098ed9b11f506e93bRomain Guy                setRequested(false);
7279745fae73b584f3e9a9c304098ed9b11f506e93bRomain Guy                Log.w(LOG_TAG, "Mountain View, we've had a problem here. "
7289745fae73b584f3e9a9c304098ed9b11f506e93bRomain Guy                        + "Switching back to software rendering.");
7299745fae73b584f3e9a9c304098ed9b11f506e93bRomain Guy            }
7309745fae73b584f3e9a9c304098ed9b11f506e93bRomain Guy        }
7319745fae73b584f3e9a9c304098ed9b11f506e93bRomain Guy
732e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        @Override
733648251710162cdaf7371012a1cbb79b9bc5bc0e4Dianne Hackborn        boolean initialize(SurfaceHolder holder) throws Surface.OutOfResourcesException {
734e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            if (isRequested() && !isEnabled()) {
735e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                initializeEgl();
736e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                mGl = createEglSurface(holder);
737fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy                mDestroyed = false;
7382d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
739e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                if (mGl != null) {
740fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy                    int err = sEgl.eglGetError();
741484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                    if (err != EGL_SUCCESS) {
7424caa4ed120a86e855d4d3b6b455c6fb9ca22e365Romain Guy                        destroy(true);
743e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                        setRequested(false);
744e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                    } else {
7454caa4ed120a86e855d4d3b6b455c6fb9ca22e365Romain Guy                        if (mCanvas == null) {
7464caa4ed120a86e855d4d3b6b455c6fb9ca22e365Romain Guy                            mCanvas = createCanvas();
747fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy                        }
748e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                        if (mCanvas != null) {
749e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                            setEnabled(true);
750e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                        } else {
751e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                            Log.w(LOG_TAG, "Hardware accelerated Canvas could not be created");
752e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                        }
753e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                    }
754e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
755e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                    return mCanvas != null;
756e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                }
757e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            }
758e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            return false;
759e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        }
7602a83f001fdb189f945e82e81e717ba204824b112Romain Guy
7612a83f001fdb189f945e82e81e717ba204824b112Romain Guy        @Override
762648251710162cdaf7371012a1cbb79b9bc5bc0e4Dianne Hackborn        void updateSurface(SurfaceHolder holder) throws Surface.OutOfResourcesException {
7632a83f001fdb189f945e82e81e717ba204824b112Romain Guy            if (isRequested() && isEnabled()) {
7642a83f001fdb189f945e82e81e717ba204824b112Romain Guy                createEglSurface(holder);
7652a83f001fdb189f945e82e81e717ba204824b112Romain Guy            }
7662a83f001fdb189f945e82e81e717ba204824b112Romain Guy        }
767e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
7685d6999e1ca457948e06792ea6259ffa947c9fa81Romain Guy        abstract HardwareCanvas createCanvas();
7692d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
77029d23ecfd8612ecd4a7b2140acd344934b73a558Romain Guy        abstract int[] getConfig(boolean dirtyRegions);
77129d23ecfd8612ecd4a7b2140acd344934b73a558Romain Guy
772e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        void initializeEgl() {
773566b3efb25299d2a9c8ae827522802bad965426aRomain Guy            synchronized (sEglLock) {
774566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                if (sEgl == null && sEglConfig == null) {
775566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                    sEgl = (EGL10) EGLContext.getEGL();
776566b3efb25299d2a9c8ae827522802bad965426aRomain Guy
777566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                    // Get to the default display.
778484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                    sEglDisplay = sEgl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
779566b3efb25299d2a9c8ae827522802bad965426aRomain Guy
780484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                    if (sEglDisplay == EGL_NO_DISPLAY) {
781566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                        throw new RuntimeException("eglGetDisplay failed "
782407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy                                + GLUtils.getEGLErrorString(sEgl.eglGetError()));
783566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                    }
784566b3efb25299d2a9c8ae827522802bad965426aRomain Guy
785566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                    // We can now initialize EGL for that display
786566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                    int[] version = new int[2];
787566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                    if (!sEgl.eglInitialize(sEglDisplay, version)) {
788566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                        throw new RuntimeException("eglInitialize failed " +
789407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy                                GLUtils.getEGLErrorString(sEgl.eglGetError()));
790566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                    }
791566b3efb25299d2a9c8ae827522802bad965426aRomain Guy
792e91a9c7ab075c43e983fdeb9af80447caa501337Romain Guy                    sEglConfig = chooseEglConfig();
793069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy                    if (sEglConfig == null) {
794566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                        // We tried to use EGL_SWAP_BEHAVIOR_PRESERVED_BIT, try again without
795566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                        if (sDirtyRegions) {
796566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                            sDirtyRegions = false;
797566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                            sEglConfig = chooseEglConfig();
798566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                            if (sEglConfig == null) {
799566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                                throw new RuntimeException("eglConfig not initialized");
800566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                            }
801566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                        } else {
802566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                            throw new RuntimeException("eglConfig not initialized");
803566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                        }
804069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy                    }
805069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy                }
806069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy            }
807566b3efb25299d2a9c8ae827522802bad965426aRomain Guy
8085d6999e1ca457948e06792ea6259ffa947c9fa81Romain Guy            ManagedEGLContext managedContext = sEglContextStorage.get();
809717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn            mEglContext = managedContext != null ? managedContext.getContext() : null;
810566b3efb25299d2a9c8ae827522802bad965426aRomain Guy            mEglThread = Thread.currentThread();
811566b3efb25299d2a9c8ae827522802bad965426aRomain Guy
812566b3efb25299d2a9c8ae827522802bad965426aRomain Guy            if (mEglContext == null) {
813566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                mEglContext = createContext(sEgl, sEglDisplay, sEglConfig);
8145d6999e1ca457948e06792ea6259ffa947c9fa81Romain Guy                sEglContextStorage.set(createManagedContext(mEglContext));
815566b3efb25299d2a9c8ae827522802bad965426aRomain Guy            }
816e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        }
817e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
8185d6999e1ca457948e06792ea6259ffa947c9fa81Romain Guy        abstract ManagedEGLContext createManagedContext(EGLContext eglContext);
8195d6999e1ca457948e06792ea6259ffa947c9fa81Romain Guy
820e91a9c7ab075c43e983fdeb9af80447caa501337Romain Guy        private EGLConfig chooseEglConfig() {
821e91a9c7ab075c43e983fdeb9af80447caa501337Romain Guy            EGLConfig[] configs = new EGLConfig[1];
822484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy            int[] configsCount = new int[1];
8237e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy            int[] configSpec = getConfig(sDirtyRegions);
824484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy
825484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy            // Debug
82629d23ecfd8612ecd4a7b2140acd344934b73a558Romain Guy            final String debug = SystemProperties.get(PRINT_CONFIG_PROPERTY, "");
827484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy            if ("all".equalsIgnoreCase(debug)) {
828484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                sEgl.eglChooseConfig(sEglDisplay, configSpec, null, 0, configsCount);
829484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy
830484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                EGLConfig[] debugConfigs = new EGLConfig[configsCount[0]];
831484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                sEgl.eglChooseConfig(sEglDisplay, configSpec, debugConfigs,
832484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                        configsCount[0], configsCount);
833484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy
834484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                for (EGLConfig config : debugConfigs) {
835484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                    printConfig(config);
836484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                }
837484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy            }
838484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy
839e91a9c7ab075c43e983fdeb9af80447caa501337Romain Guy            if (!sEgl.eglChooseConfig(sEglDisplay, configSpec, configs, 1, configsCount)) {
840e91a9c7ab075c43e983fdeb9af80447caa501337Romain Guy                throw new IllegalArgumentException("eglChooseConfig failed " +
841407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy                        GLUtils.getEGLErrorString(sEgl.eglGetError()));
842e91a9c7ab075c43e983fdeb9af80447caa501337Romain Guy            } else if (configsCount[0] > 0) {
843484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                if ("choice".equalsIgnoreCase(debug)) {
844484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                    printConfig(configs[0]);
845484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                }
846e91a9c7ab075c43e983fdeb9af80447caa501337Romain Guy                return configs[0];
847e91a9c7ab075c43e983fdeb9af80447caa501337Romain Guy            }
848484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy
849e91a9c7ab075c43e983fdeb9af80447caa501337Romain Guy            return null;
850e91a9c7ab075c43e983fdeb9af80447caa501337Romain Guy        }
851e91a9c7ab075c43e983fdeb9af80447caa501337Romain Guy
852e979e62ac7313b7cffe9b131bb8a99c356068b45Romain Guy        private static void printConfig(EGLConfig config) {
853484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy            int[] value = new int[1];
854484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy
855484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy            Log.d(LOG_TAG, "EGL configuration " + config + ":");
856484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy
857484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy            sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_RED_SIZE, value);
858484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy            Log.d(LOG_TAG, "  RED_SIZE = " + value[0]);
859484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy
860484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy            sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_GREEN_SIZE, value);
861484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy            Log.d(LOG_TAG, "  GREEN_SIZE = " + value[0]);
862484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy
863484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy            sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_BLUE_SIZE, value);
864484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy            Log.d(LOG_TAG, "  BLUE_SIZE = " + value[0]);
865484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy
866484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy            sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_ALPHA_SIZE, value);
867484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy            Log.d(LOG_TAG, "  ALPHA_SIZE = " + value[0]);
868484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy
869484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy            sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_DEPTH_SIZE, value);
870484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy            Log.d(LOG_TAG, "  DEPTH_SIZE = " + value[0]);
871484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy
872484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy            sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_STENCIL_SIZE, value);
873484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy            Log.d(LOG_TAG, "  STENCIL_SIZE = " + value[0]);
874484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy
875484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy            sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_SURFACE_TYPE, value);
87629d23ecfd8612ecd4a7b2140acd344934b73a558Romain Guy            Log.d(LOG_TAG, "  SURFACE_TYPE = 0x" + Integer.toHexString(value[0]));
877484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy        }
878484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy
879648251710162cdaf7371012a1cbb79b9bc5bc0e4Dianne Hackborn        GL createEglSurface(SurfaceHolder holder) throws Surface.OutOfResourcesException {
880e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            // Check preconditions.
881fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy            if (sEgl == null) {
882e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                throw new RuntimeException("egl not initialized");
883e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            }
884fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy            if (sEglDisplay == null) {
885e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                throw new RuntimeException("eglDisplay not initialized");
886e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            }
887fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy            if (sEglConfig == null) {
888069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy                throw new RuntimeException("eglConfig not initialized");
889e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            }
890566b3efb25299d2a9c8ae827522802bad965426aRomain Guy            if (Thread.currentThread() != mEglThread) {
891fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy                throw new IllegalStateException("HardwareRenderer cannot be used "
892fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy                        + "from multiple threads");
893fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy            }
894e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
8956d7475d666baefaa3ba9f0dcee25238739454241Romain Guy            // In case we need to destroy an existing surface
8966d7475d666baefaa3ba9f0dcee25238739454241Romain Guy            destroySurface();
897e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
898e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            // Create an EGL surface we can render into.
8991d0c708961f824ac5171238c205a7bf328d5d8a5Romain Guy            if (!createSurface(holder)) {
9001d0c708961f824ac5171238c205a7bf328d5d8a5Romain Guy                return null;
901e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            }
902e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
9032d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy            /*
9042d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy             * Before we can issue GL commands, we need to make sure
9052d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy             * the context is current and bound to a surface.
9062d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy             */
907566b3efb25299d2a9c8ae827522802bad965426aRomain Guy            if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
908648251710162cdaf7371012a1cbb79b9bc5bc0e4Dianne Hackborn                throw new Surface.OutOfResourcesException("eglMakeCurrent failed "
909407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy                        + GLUtils.getEGLErrorString(sEgl.eglGetError()));
910e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            }
9118ff6b9ebeeb24a6161ec6098e6bfdf8790ee5695Romain Guy
9128ff6b9ebeeb24a6161ec6098e6bfdf8790ee5695Romain Guy            initCaches();
9136f7d9394ec69e9fb38ca5fc2caf6d2aef6f7442dRomain Guy
9149477c6e6581ce97976250951f33e1297604ac777Romain Guy            enableDirtyRegions();
9159477c6e6581ce97976250951f33e1297604ac777Romain Guy
9169477c6e6581ce97976250951f33e1297604ac777Romain Guy            return mEglContext.getGL();
9179477c6e6581ce97976250951f33e1297604ac777Romain Guy        }
9189477c6e6581ce97976250951f33e1297604ac777Romain Guy
9199477c6e6581ce97976250951f33e1297604ac777Romain Guy        private void enableDirtyRegions() {
9206f7d9394ec69e9fb38ca5fc2caf6d2aef6f7442dRomain Guy            // If mDirtyRegions is set, this means we have an EGL configuration
9216f7d9394ec69e9fb38ca5fc2caf6d2aef6f7442dRomain Guy            // with EGL_SWAP_BEHAVIOR_PRESERVED_BIT set
9227e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy            if (sDirtyRegions) {
923244ada1d35419b7be9de0fc833bb03955b725ffaRomain Guy                if (!(mDirtyRegionsEnabled = preserveBackBuffer())) {
9247d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                    Log.w(LOG_TAG, "Backbuffer cannot be preserved");
9257d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                }
9267e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy            } else if (sDirtyRegionsRequested) {
9276f7d9394ec69e9fb38ca5fc2caf6d2aef6f7442dRomain Guy                // If mDirtyRegions is not set, our EGL configuration does not
9286f7d9394ec69e9fb38ca5fc2caf6d2aef6f7442dRomain Guy                // have EGL_SWAP_BEHAVIOR_PRESERVED_BIT; however, the default
9296f7d9394ec69e9fb38ca5fc2caf6d2aef6f7442dRomain Guy                // swap behavior might be EGL_BUFFER_PRESERVED, which means we
9306f7d9394ec69e9fb38ca5fc2caf6d2aef6f7442dRomain Guy                // want to set mDirtyRegions. We try to do this only if dirty
9316f7d9394ec69e9fb38ca5fc2caf6d2aef6f7442dRomain Guy                // regions were initially requested as part of the device
9326f7d9394ec69e9fb38ca5fc2caf6d2aef6f7442dRomain Guy                // configuration (see RENDER_DIRTY_REGIONS)
933244ada1d35419b7be9de0fc833bb03955b725ffaRomain Guy                mDirtyRegionsEnabled = isBackBufferPreserved();
9347d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy            }
9352d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        }
9362d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
9378ff6b9ebeeb24a6161ec6098e6bfdf8790ee5695Romain Guy        abstract void initCaches();
9388ff6b9ebeeb24a6161ec6098e6bfdf8790ee5695Romain Guy
939e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
940912a7b32d0c59ba38265c5dd6ff84ce93f909a7fRomain Guy            int[] attribs = { EGL_CONTEXT_CLIENT_VERSION, mGlVersion, EGL_NONE };
941e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
942484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy            return egl.eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT,
943912a7b32d0c59ba38265c5dd6ff84ce93f909a7fRomain Guy                    mGlVersion != 0 ? attribs : null);
944e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        }
945e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
946e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        @Override
9474caa4ed120a86e855d4d3b6b455c6fb9ca22e365Romain Guy        void destroy(boolean full) {
9484caa4ed120a86e855d4d3b6b455c6fb9ca22e365Romain Guy            if (full && mCanvas != null) {
9494caa4ed120a86e855d4d3b6b455c6fb9ca22e365Romain Guy                mCanvas = null;
9504caa4ed120a86e855d4d3b6b455c6fb9ca22e365Romain Guy            }
951fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy
952357c942462e4eb1d0b2e91b3fe8ec9ac7524bbedRomain Guy            if (!isEnabled() || mDestroyed) {
953357c942462e4eb1d0b2e91b3fe8ec9ac7524bbedRomain Guy                setEnabled(false);
954357c942462e4eb1d0b2e91b3fe8ec9ac7524bbedRomain Guy                return;
955357c942462e4eb1d0b2e91b3fe8ec9ac7524bbedRomain Guy            }
956e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
9576d7475d666baefaa3ba9f0dcee25238739454241Romain Guy            destroySurface();
958357c942462e4eb1d0b2e91b3fe8ec9ac7524bbedRomain Guy            setEnabled(false);
9592d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
960357c942462e4eb1d0b2e91b3fe8ec9ac7524bbedRomain Guy            mDestroyed = true;
961e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            mGl = null;
962fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        }
963fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy
9646d7475d666baefaa3ba9f0dcee25238739454241Romain Guy        void destroySurface() {
9656d7475d666baefaa3ba9f0dcee25238739454241Romain Guy            if (mEglSurface != null && mEglSurface != EGL_NO_SURFACE) {
9666d7475d666baefaa3ba9f0dcee25238739454241Romain Guy                sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
9676d7475d666baefaa3ba9f0dcee25238739454241Romain Guy                sEgl.eglDestroySurface(sEglDisplay, mEglSurface);
9686d7475d666baefaa3ba9f0dcee25238739454241Romain Guy                mEglSurface = null;
9696d7475d666baefaa3ba9f0dcee25238739454241Romain Guy            }
9706d7475d666baefaa3ba9f0dcee25238739454241Romain Guy        }
9716d7475d666baefaa3ba9f0dcee25238739454241Romain Guy
9722d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        @Override
973cf15efba0792b052dca5baa350d9fb00e6a60667Romain Guy        void invalidate(SurfaceHolder holder) {
9747e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy            // Cancels any existing buffer to ensure we'll get a buffer
9757e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy            // of the right size before we call eglSwapBuffers
976cf15efba0792b052dca5baa350d9fb00e6a60667Romain Guy            sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
9771d0c708961f824ac5171238c205a7bf328d5d8a5Romain Guy
978d3facf341bf106588aade72c0164532cd4bf941fRomain Guy            if (mEglSurface != null && mEglSurface != EGL_NO_SURFACE) {
979d3facf341bf106588aade72c0164532cd4bf941fRomain Guy                sEgl.eglDestroySurface(sEglDisplay, mEglSurface);
9801d0c708961f824ac5171238c205a7bf328d5d8a5Romain Guy                mEglSurface = null;
9811d0c708961f824ac5171238c205a7bf328d5d8a5Romain Guy                setEnabled(false);
982d3facf341bf106588aade72c0164532cd4bf941fRomain Guy            }
983cf15efba0792b052dca5baa350d9fb00e6a60667Romain Guy
984d3facf341bf106588aade72c0164532cd4bf941fRomain Guy            if (holder.getSurface().isValid()) {
9851d0c708961f824ac5171238c205a7bf328d5d8a5Romain Guy                if (!createSurface(holder)) {
9861d0c708961f824ac5171238c205a7bf328d5d8a5Romain Guy                    return;
987cf15efba0792b052dca5baa350d9fb00e6a60667Romain Guy                }
9889477c6e6581ce97976250951f33e1297604ac777Romain Guy
9899477c6e6581ce97976250951f33e1297604ac777Romain Guy                mUpdateDirtyRegions = true;
9909477c6e6581ce97976250951f33e1297604ac777Romain Guy
99186e3e22ba81fb75a5c7e5e007ca1c0cacfda3afbRomain Guy                if (mCanvas != null) {
99286e3e22ba81fb75a5c7e5e007ca1c0cacfda3afbRomain Guy                    setEnabled(true);
99386e3e22ba81fb75a5c7e5e007ca1c0cacfda3afbRomain Guy                }
9941d0c708961f824ac5171238c205a7bf328d5d8a5Romain Guy            }
9951d0c708961f824ac5171238c205a7bf328d5d8a5Romain Guy        }
9961d0c708961f824ac5171238c205a7bf328d5d8a5Romain Guy
9971d0c708961f824ac5171238c205a7bf328d5d8a5Romain Guy        private boolean createSurface(SurfaceHolder holder) {
9981d0c708961f824ac5171238c205a7bf328d5d8a5Romain Guy            mEglSurface = sEgl.eglCreateWindowSurface(sEglDisplay, sEglConfig, holder, null);
9991d0c708961f824ac5171238c205a7bf328d5d8a5Romain Guy
10001d0c708961f824ac5171238c205a7bf328d5d8a5Romain Guy            if (mEglSurface == null || mEglSurface == EGL_NO_SURFACE) {
10011d0c708961f824ac5171238c205a7bf328d5d8a5Romain Guy                int error = sEgl.eglGetError();
10021d0c708961f824ac5171238c205a7bf328d5d8a5Romain Guy                if (error == EGL_BAD_NATIVE_WINDOW) {
10031d0c708961f824ac5171238c205a7bf328d5d8a5Romain Guy                    Log.e(LOG_TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
10041d0c708961f824ac5171238c205a7bf328d5d8a5Romain Guy                    return false;
10051d0c708961f824ac5171238c205a7bf328d5d8a5Romain Guy                }
10061d0c708961f824ac5171238c205a7bf328d5d8a5Romain Guy                throw new RuntimeException("createWindowSurface failed "
1007407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy                        + GLUtils.getEGLErrorString(error));
1008cf15efba0792b052dca5baa350d9fb00e6a60667Romain Guy            }
10091d0c708961f824ac5171238c205a7bf328d5d8a5Romain Guy            return true;
1010039857520b1a03a52051b966d87d587225bdfcc3Romain Guy        }
1011cf15efba0792b052dca5baa350d9fb00e6a60667Romain Guy
1012039857520b1a03a52051b966d87d587225bdfcc3Romain Guy        @Override
1013039857520b1a03a52051b966d87d587225bdfcc3Romain Guy        boolean validate() {
1014039857520b1a03a52051b966d87d587225bdfcc3Romain Guy            return checkCurrent() != SURFACE_STATE_ERROR;
10157e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy        }
10167e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy
10177e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy        @Override
1018fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        void setup(int width, int height) {
1019eca9b1f53c2c291cbfb89b5f3cc45db7bdca6c7dRomain Guy            if (validate()) {
1020eca9b1f53c2c291cbfb89b5f3cc45db7bdca6c7dRomain Guy                mCanvas.setViewport(width, height);
102140e0383dce630ed9b2b1aa0e497709b89dfab6efChet Haase                mWidth = width;
102240e0383dce630ed9b2b1aa0e497709b89dfab6efChet Haase                mHeight = height;
1023eca9b1f53c2c291cbfb89b5f3cc45db7bdca6c7dRomain Guy            }
1024e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        }
10257d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy
102640e0383dce630ed9b2b1aa0e497709b89dfab6efChet Haase        @Override
102740e0383dce630ed9b2b1aa0e497709b89dfab6efChet Haase        int getWidth() {
102840e0383dce630ed9b2b1aa0e497709b89dfab6efChet Haase            return mWidth;
102940e0383dce630ed9b2b1aa0e497709b89dfab6efChet Haase        }
103040e0383dce630ed9b2b1aa0e497709b89dfab6efChet Haase
103140e0383dce630ed9b2b1aa0e497709b89dfab6efChet Haase        @Override
103240e0383dce630ed9b2b1aa0e497709b89dfab6efChet Haase        int getHeight() {
103340e0383dce630ed9b2b1aa0e497709b89dfab6efChet Haase            return mHeight;
103440e0383dce630ed9b2b1aa0e497709b89dfab6efChet Haase        }
103540e0383dce630ed9b2b1aa0e497709b89dfab6efChet Haase
103608837c246c9c27902c59b41c8661c2f27a4aa2bcChet Haase        @Override
103708837c246c9c27902c59b41c8661c2f27a4aa2bcChet Haase        HardwareCanvas getCanvas() {
103808837c246c9c27902c59b41c8661c2f27a4aa2bcChet Haase            return mCanvas;
103908837c246c9c27902c59b41c8661c2f27a4aa2bcChet Haase        }
104008837c246c9c27902c59b41c8661c2f27a4aa2bcChet Haase
1041e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        boolean canDraw() {
1042e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            return mGl != null && mCanvas != null;
1043e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        }
1044e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
104544b2fe3fc114ee5f7273c6b0fee2cc999bf244a2Chet Haase        int onPreDraw(Rect dirty) {
104644b2fe3fc114ee5f7273c6b0fee2cc999bf244a2Chet Haase            return DisplayList.STATUS_DONE;
1047e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        }
1048e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
1049b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy        void onPostDraw() {
1050b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy        }
10512d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
10528f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy        class FunctorsRunnable implements Runnable {
10538f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy            View.AttachInfo attachInfo;
10548f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy
10558f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy            @Override
10568f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy            public void run() {
10578f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy                final HardwareRenderer renderer = attachInfo.mHardwareRenderer;
10588f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy                if (renderer == null || !renderer.isEnabled() || renderer != GlRenderer.this) {
10598f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy                    return;
10608f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy                }
10618f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy
10628f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy                final int surfaceState = checkCurrent();
10638f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy                if (surfaceState != SURFACE_STATE_ERROR) {
10648f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy                    int status = mCanvas.invokeFunctors(mRedrawClip);
10658f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy                    handleFunctorStatus(attachInfo, status);
10668f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy                }
10678f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy            }
10688f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy        }
10698f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy
10702d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        @Override
107150d133e290468fd149b5c03e46549afca2ee05f8Romain Guy        boolean draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks,
10727d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                Rect dirty) {
1073e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            if (canDraw()) {
107402ccac69fd1c0a03c24c5f3ace0ad4bed337b1fdRomain Guy                if (!hasDirtyRegions()) {
10757d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                    dirty = null;
10767d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                }
10772d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy                attachInfo.mIgnoreDirtyState = true;
107802ccac69fd1c0a03c24c5f3ace0ad4bed337b1fdRomain Guy                attachInfo.mDrawingTime = SystemClock.uptimeMillis();
107902ccac69fd1c0a03c24c5f3ace0ad4bed337b1fdRomain Guy
10802d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy                view.mPrivateFlags |= View.DRAWN;
1081039857520b1a03a52051b966d87d587225bdfcc3Romain Guy
1082d88f54c5c4ce59585b8b9e6009836f14c00be743Romain Guy                final int surfaceState = checkCurrent();
1083d88f54c5c4ce59585b8b9e6009836f14c00be743Romain Guy                if (surfaceState != SURFACE_STATE_ERROR) {
10847687882800f49e3fc3a14f1d7540412f77d6bd4dRomain Guy                    HardwareCanvas canvas = mCanvas;
10857687882800f49e3fc3a14f1d7540412f77d6bd4dRomain Guy                    attachInfo.mHardwareCanvas = canvas;
10867687882800f49e3fc3a14f1d7540412f77d6bd4dRomain Guy
1087d88f54c5c4ce59585b8b9e6009836f14c00be743Romain Guy                    // We had to change the current surface and/or context, redraw everything
1088d88f54c5c4ce59585b8b9e6009836f14c00be743Romain Guy                    if (surfaceState == SURFACE_STATE_UPDATED) {
1089d88f54c5c4ce59585b8b9e6009836f14c00be743Romain Guy                        dirty = null;
10907687882800f49e3fc3a14f1d7540412f77d6bd4dRomain Guy                        beginFrame(null);
10917687882800f49e3fc3a14f1d7540412f77d6bd4dRomain Guy                    } else {
10927687882800f49e3fc3a14f1d7540412f77d6bd4dRomain Guy                        int[] size = mSurfaceSize;
10937687882800f49e3fc3a14f1d7540412f77d6bd4dRomain Guy                        beginFrame(size);
10947687882800f49e3fc3a14f1d7540412f77d6bd4dRomain Guy
10957687882800f49e3fc3a14f1d7540412f77d6bd4dRomain Guy                        if (size[1] != mHeight || size[0] != mWidth) {
10967687882800f49e3fc3a14f1d7540412f77d6bd4dRomain Guy                            mWidth = size[0];
10977687882800f49e3fc3a14f1d7540412f77d6bd4dRomain Guy                            mHeight = size[1];
10987687882800f49e3fc3a14f1d7540412f77d6bd4dRomain Guy
10997687882800f49e3fc3a14f1d7540412f77d6bd4dRomain Guy                            canvas.setViewport(mWidth, mHeight);
11007687882800f49e3fc3a14f1d7540412f77d6bd4dRomain Guy
11017687882800f49e3fc3a14f1d7540412f77d6bd4dRomain Guy                            dirty = null;
11027687882800f49e3fc3a14f1d7540412f77d6bd4dRomain Guy                        }
1103d88f54c5c4ce59585b8b9e6009836f14c00be743Romain Guy                    }
1104d88f54c5c4ce59585b8b9e6009836f14c00be743Romain Guy
110544b2fe3fc114ee5f7273c6b0fee2cc999bf244a2Chet Haase                    int status = onPreDraw(dirty);
1106b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy                    int saveCount = canvas.save();
1107b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy                    callbacks.onHardwarePreDraw(canvas);
1108daf98e941e140e8739458126640183b9f296a2abChet Haase
1109b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy                    try {
1110daf98e941e140e8739458126640183b9f296a2abChet Haase                        view.mRecreateDisplayList =
1111daf98e941e140e8739458126640183b9f296a2abChet Haase                                (view.mPrivateFlags & View.INVALIDATED) == View.INVALIDATED;
1112daf98e941e140e8739458126640183b9f296a2abChet Haase                        view.mPrivateFlags &= ~View.INVALIDATED;
11137d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy
1114a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy                        long getDisplayListStartTime = 0;
1115a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy                        if (mProfileEnabled) {
1116a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy                            mProfileCurrentFrame += PROFILE_FRAME_DATA_COUNT;
1117a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy                            if (mProfileCurrentFrame >= mProfileData.length) {
1118a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy                                mProfileCurrentFrame = 0;
1119a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy                            }
1120a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy
112195db2b20d7bc0aaf00b1d4418124f5cf0a755d74Jeff Brown                            getDisplayListStartTime = System.nanoTime();
112295db2b20d7bc0aaf00b1d4418124f5cf0a755d74Jeff Brown                        }
112395db2b20d7bc0aaf00b1d4418124f5cf0a755d74Jeff Brown
1124daf98e941e140e8739458126640183b9f296a2abChet Haase                        DisplayList displayList = view.getDisplayList();
112595db2b20d7bc0aaf00b1d4418124f5cf0a755d74Jeff Brown
1126a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy                        if (mProfileEnabled) {
112795db2b20d7bc0aaf00b1d4418124f5cf0a755d74Jeff Brown                            long now = System.nanoTime();
1128a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy                            float total = (now - getDisplayListStartTime) * 0.000001f;
1129a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy                            //noinspection PointlessArithmeticExpression
1130a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy                            mProfileData[mProfileCurrentFrame] = total;
113195db2b20d7bc0aaf00b1d4418124f5cf0a755d74Jeff Brown                        }
113295db2b20d7bc0aaf00b1d4418124f5cf0a755d74Jeff Brown
1133daf98e941e140e8739458126640183b9f296a2abChet Haase                        if (displayList != null) {
1134a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy                            long drawDisplayListStartTime = 0;
1135a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy                            if (mProfileEnabled) {
113695db2b20d7bc0aaf00b1d4418124f5cf0a755d74Jeff Brown                                drawDisplayListStartTime = System.nanoTime();
113795db2b20d7bc0aaf00b1d4418124f5cf0a755d74Jeff Brown                            }
113895db2b20d7bc0aaf00b1d4418124f5cf0a755d74Jeff Brown
113944b2fe3fc114ee5f7273c6b0fee2cc999bf244a2Chet Haase                            status |= canvas.drawDisplayList(displayList, mRedrawClip,
114033f6beb10f98e8ba96250e284876d607055d278dRomain Guy                                    DisplayList.FLAG_CLIP_CHILDREN);
114195db2b20d7bc0aaf00b1d4418124f5cf0a755d74Jeff Brown
1142a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy                            if (mProfileEnabled) {
114395db2b20d7bc0aaf00b1d4418124f5cf0a755d74Jeff Brown                                long now = System.nanoTime();
1144a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy                                float total = (now - drawDisplayListStartTime) * 0.000001f;
1145a676ad7e34c9afbaafaeca8c3fe96e95c518828eRomain Guy                                mProfileData[mProfileCurrentFrame + 1] = total;
114695db2b20d7bc0aaf00b1d4418124f5cf0a755d74Jeff Brown                            }
114795db2b20d7bc0aaf00b1d4418124f5cf0a755d74Jeff Brown
11488f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy                            handleFunctorStatus(attachInfo, status);
1149daf98e941e140e8739458126640183b9f296a2abChet Haase                        } else {
1150daf98e941e140e8739458126640183b9f296a2abChet Haase                            // Shouldn't reach here
1151daf98e941e140e8739458126640183b9f296a2abChet Haase                            view.draw(canvas);
1152daf98e941e140e8739458126640183b9f296a2abChet Haase                        }
1153b04f7e9438e8f73081f9be3fda166098042263a5Romain Guy                    } finally {
1154b04f7e9438e8f73081f9be3fda166098042263a5Romain Guy                        callbacks.onHardwarePostDraw(canvas);
1155b04f7e9438e8f73081f9be3fda166098042263a5Romain Guy                        canvas.restoreToCount(saveCount);
1156b04f7e9438e8f73081f9be3fda166098042263a5Romain Guy                        view.mRecreateDisplayList = false;
115719f86e831ee0629b24385b0bb51d27ff91961dd2Romain Guy
1158a3fabff98590d26f0c362cb09dc378fece66215cMichael Jurka                        mFrameCount++;
115919f86e831ee0629b24385b0bb51d27ff91961dd2Romain Guy
1160b04f7e9438e8f73081f9be3fda166098042263a5Romain Guy                        if (mDebugDirtyRegions) {
11617d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                            if (mDebugPaint == null) {
11627d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                                mDebugPaint = new Paint();
11637d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                                mDebugPaint.setColor(0x7fff0000);
11647d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                            }
116519f86e831ee0629b24385b0bb51d27ff91961dd2Romain Guy
1166a3fabff98590d26f0c362cb09dc378fece66215cMichael Jurka                            if (dirty != null && (mFrameCount & 1) == 0) {
11677d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                                canvas.drawRect(dirty, mDebugPaint);
11687d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                            }
11697d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                        }
1170b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy                    }
1171daf98e941e140e8739458126640183b9f296a2abChet Haase
1172b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy                    onPostDraw();
1173daf98e941e140e8739458126640183b9f296a2abChet Haase
1174b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy                    attachInfo.mIgnoreDirtyState = false;
1175486590963e2207d68eebd6944fec70d50d41116aChet Haase
1176486590963e2207d68eebd6944fec70d50d41116aChet Haase                    if ((status & DisplayList.STATUS_DREW) == DisplayList.STATUS_DREW) {
11774e91a180be46c0c7c3bf398d4df4cbe2404216b5Jeff Brown
1178486590963e2207d68eebd6944fec70d50d41116aChet Haase                        long eglSwapBuffersStartTime = 0;
1179486590963e2207d68eebd6944fec70d50d41116aChet Haase                        if (mProfileEnabled) {
1180486590963e2207d68eebd6944fec70d50d41116aChet Haase                            eglSwapBuffersStartTime = System.nanoTime();
1181486590963e2207d68eebd6944fec70d50d41116aChet Haase                        }
1182486590963e2207d68eebd6944fec70d50d41116aChet Haase
1183486590963e2207d68eebd6944fec70d50d41116aChet Haase                        sEgl.eglSwapBuffers(sEglDisplay, mEglSurface);
1184486590963e2207d68eebd6944fec70d50d41116aChet Haase
1185486590963e2207d68eebd6944fec70d50d41116aChet Haase                        if (mProfileEnabled) {
1186486590963e2207d68eebd6944fec70d50d41116aChet Haase                            long now = System.nanoTime();
1187486590963e2207d68eebd6944fec70d50d41116aChet Haase                            float total = (now - eglSwapBuffersStartTime) * 0.000001f;
1188486590963e2207d68eebd6944fec70d50d41116aChet Haase                            mProfileData[mProfileCurrentFrame + 2] = total;
1189486590963e2207d68eebd6944fec70d50d41116aChet Haase                        }
1190486590963e2207d68eebd6944fec70d50d41116aChet Haase
1191486590963e2207d68eebd6944fec70d50d41116aChet Haase                        checkEglErrors();
119295db2b20d7bc0aaf00b1d4418124f5cf0a755d74Jeff Brown                    }
119395db2b20d7bc0aaf00b1d4418124f5cf0a755d74Jeff Brown
119450d133e290468fd149b5c03e46549afca2ee05f8Romain Guy                    return dirty == null;
11959a40babc62416259d18783ce8c03c00042ec317bRomain Guy                }
11962d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy            }
119750d133e290468fd149b5c03e46549afca2ee05f8Romain Guy
119850d133e290468fd149b5c03e46549afca2ee05f8Romain Guy            return false;
11992d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        }
1200039857520b1a03a52051b966d87d587225bdfcc3Romain Guy
12018f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy        private void handleFunctorStatus(View.AttachInfo attachInfo, int status) {
12028f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy            // If the draw flag is set, functors will be invoked while executing
12038f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy            // the tree of display lists
12048f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy            if ((status & DisplayList.STATUS_DRAW) != 0) {
12058f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy                if (mRedrawClip.isEmpty()) {
12068f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy                    attachInfo.mViewRootImpl.invalidate();
12078f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy                } else {
12088f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy                    attachInfo.mViewRootImpl.invalidateChildInParent(null, mRedrawClip);
12098f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy                    mRedrawClip.setEmpty();
12108f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy                }
12118f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy            }
12128f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy
12138f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy            if ((status & DisplayList.STATUS_INVOKE) != 0) {
1214ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy                scheduleFunctors(attachInfo);
1215ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy            }
1216ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy        }
1217ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy
1218ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy        private void scheduleFunctors(View.AttachInfo attachInfo) {
1219ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy            mFunctorsRunnable.attachInfo = attachInfo;
1220ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy            if (!attachInfo.mHandler.hasCallbacks(mFunctorsRunnable)) {
12218f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy                // delay the functor callback by a few ms so it isn't polled constantly
12228f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy                attachInfo.mHandler.postDelayed(mFunctorsRunnable, FUNCTOR_PROCESS_DELAY);
12238f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy            }
12248f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy        }
12258f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy
1226ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy        @Override
1227ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy        void detachFunctor(int functor) {
1228ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy            if (mCanvas != null) {
1229ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy                mCanvas.detachFunctor(functor);
1230932b7f6765968bd526c03512f3805fbc3924dc29Chris Craik            }
1231ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy        }
1232ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy
1233ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy        @Override
123441ee465734d0006797a8fd36e88976c1e85d161cChris Craik        boolean attachFunctor(View.AttachInfo attachInfo, int functor) {
1235ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy            if (mCanvas != null) {
1236ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy                mCanvas.attachFunctor(functor);
1237ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy                scheduleFunctors(attachInfo);
123841ee465734d0006797a8fd36e88976c1e85d161cChris Craik                return true;
1239ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy            }
124041ee465734d0006797a8fd36e88976c1e85d161cChris Craik            return false;
1241ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy        }
1242ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy
1243039857520b1a03a52051b966d87d587225bdfcc3Romain Guy        /**
1244566b3efb25299d2a9c8ae827522802bad965426aRomain Guy         * Ensures the current EGL context is the one we expect.
1245039857520b1a03a52051b966d87d587225bdfcc3Romain Guy         *
1246039857520b1a03a52051b966d87d587225bdfcc3Romain Guy         * @return {@link #SURFACE_STATE_ERROR} if the correct EGL context cannot be made current,
1247039857520b1a03a52051b966d87d587225bdfcc3Romain Guy         *         {@link #SURFACE_STATE_UPDATED} if the EGL context was changed or
1248039857520b1a03a52051b966d87d587225bdfcc3Romain Guy         *         {@link #SURFACE_STATE_SUCCESS} if the EGL context was the correct one
1249039857520b1a03a52051b966d87d587225bdfcc3Romain Guy         */
1250912a7b32d0c59ba38265c5dd6ff84ce93f909a7fRomain Guy        int checkCurrent() {
1251566b3efb25299d2a9c8ae827522802bad965426aRomain Guy            if (mEglThread != Thread.currentThread()) {
1252039857520b1a03a52051b966d87d587225bdfcc3Romain Guy                throw new IllegalStateException("Hardware acceleration can only be used with a " +
1253566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                        "single UI thread.\nOriginal thread: " + mEglThread + "\n" +
1254039857520b1a03a52051b966d87d587225bdfcc3Romain Guy                        "Current thread: " + Thread.currentThread());
1255039857520b1a03a52051b966d87d587225bdfcc3Romain Guy            }
1256039857520b1a03a52051b966d87d587225bdfcc3Romain Guy
1257566b3efb25299d2a9c8ae827522802bad965426aRomain Guy            if (!mEglContext.equals(sEgl.eglGetCurrentContext()) ||
1258484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                    !mEglSurface.equals(sEgl.eglGetCurrentSurface(EGL_DRAW))) {
1259566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
12609745fae73b584f3e9a9c304098ed9b11f506e93bRomain Guy                    Log.e(LOG_TAG, "eglMakeCurrent failed " +
1261407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy                            GLUtils.getEGLErrorString(sEgl.eglGetError()));
1262eca9b1f53c2c291cbfb89b5f3cc45db7bdca6c7dRomain Guy                    fallback(true);
1263d88f54c5c4ce59585b8b9e6009836f14c00be743Romain Guy                    return SURFACE_STATE_ERROR;
1264d88f54c5c4ce59585b8b9e6009836f14c00be743Romain Guy                } else {
12659477c6e6581ce97976250951f33e1297604ac777Romain Guy                    if (mUpdateDirtyRegions) {
12669477c6e6581ce97976250951f33e1297604ac777Romain Guy                        enableDirtyRegions();
12679477c6e6581ce97976250951f33e1297604ac777Romain Guy                        mUpdateDirtyRegions = false;
12689477c6e6581ce97976250951f33e1297604ac777Romain Guy                    }
1269d88f54c5c4ce59585b8b9e6009836f14c00be743Romain Guy                    return SURFACE_STATE_UPDATED;
1270fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy                }
1271fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy            }
1272d88f54c5c4ce59585b8b9e6009836f14c00be743Romain Guy            return SURFACE_STATE_SUCCESS;
1273fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        }
1274e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy    }
1275fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy
1276e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy    /**
1277e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy     * Hardware renderer using OpenGL ES 2.0.
1278e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy     */
1279e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy    static class Gl20Renderer extends GlRenderer {
1280e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        private GLES20Canvas mGlCanvas;
1281e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
1282912a7b32d0c59ba38265c5dd6ff84ce93f909a7fRomain Guy        private static EGLSurface sPbuffer;
1283912a7b32d0c59ba38265c5dd6ff84ce93f909a7fRomain Guy        private static final Object[] sPbufferLock = new Object[0];
1284912a7b32d0c59ba38265c5dd6ff84ce93f909a7fRomain Guy
128531f2c2e94656530fbf6282803e62edb47e9a894dRomain Guy        static class Gl20RendererEglContext extends ManagedEGLContext {
1286717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn            final Handler mHandler = new Handler();
1287717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn
128831f2c2e94656530fbf6282803e62edb47e9a894dRomain Guy            public Gl20RendererEglContext(EGLContext context) {
1289717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn                super(context);
1290717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn            }
1291717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn
1292717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn            @Override
1293717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn            public void onTerminate(final EGLContext eglContext) {
1294717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn                // Make sure we do this on the correct thread.
1295717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn                if (mHandler.getLooper() != Looper.myLooper()) {
1296717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn                    mHandler.post(new Runnable() {
12975d6999e1ca457948e06792ea6259ffa947c9fa81Romain Guy                        @Override
12985d6999e1ca457948e06792ea6259ffa947c9fa81Romain Guy                        public void run() {
1299717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn                            onTerminate(eglContext);
1300717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn                        }
1301717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn                    });
1302717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn                    return;
1303717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn                }
1304717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn
1305717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn                synchronized (sEglLock) {
1306717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn                    if (sEgl == null) return;
1307717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn
1308717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn                    if (EGLImpl.getInitCount(sEglDisplay) == 1) {
1309717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn                        usePbufferSurface(eglContext);
1310717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn                        GLES20Canvas.terminateCaches();
1311717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn
1312717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn                        sEgl.eglDestroyContext(sEglDisplay, eglContext);
1313a998dff5d49a423aaf7097aa8f96bf5bdc681d25Romain Guy                        sEglContextStorage.set(null);
1314717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn                        sEglContextStorage.remove();
1315717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn
1316717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn                        sEgl.eglDestroySurface(sEglDisplay, sPbuffer);
131731f2c2e94656530fbf6282803e62edb47e9a894dRomain Guy                        sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE,
131831f2c2e94656530fbf6282803e62edb47e9a894dRomain Guy                                EGL_NO_SURFACE, EGL_NO_CONTEXT);
1319717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn
1320717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn                        sEgl.eglReleaseThread();
1321717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn                        sEgl.eglTerminate(sEglDisplay);
1322717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn
1323717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn                        sEgl = null;
1324717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn                        sEglDisplay = null;
1325717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn                        sEglConfig = null;
1326717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn                        sPbuffer = null;
1327717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn                    }
1328717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn                }
1329717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn            }
1330717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn        }
1331717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn
1332e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        Gl20Renderer(boolean translucent) {
1333e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            super(2, translucent);
1334e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        }
1335e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
13362d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        @Override
13375d6999e1ca457948e06792ea6259ffa947c9fa81Romain Guy        HardwareCanvas createCanvas() {
13386b7bd24659fb175fe1f0e97c86c18969918b496aRomain Guy            return mGlCanvas = new GLES20Canvas(mTranslucent);
1339e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        }
1340e91a9c7ab075c43e983fdeb9af80447caa501337Romain Guy
1341e91a9c7ab075c43e983fdeb9af80447caa501337Romain Guy        @Override
13425d6999e1ca457948e06792ea6259ffa947c9fa81Romain Guy        ManagedEGLContext createManagedContext(EGLContext eglContext) {
13435d6999e1ca457948e06792ea6259ffa947c9fa81Romain Guy            return new Gl20Renderer.Gl20RendererEglContext(mEglContext);
13445d6999e1ca457948e06792ea6259ffa947c9fa81Romain Guy        }
13455d6999e1ca457948e06792ea6259ffa947c9fa81Romain Guy
13465d6999e1ca457948e06792ea6259ffa947c9fa81Romain Guy        @Override
1347e91a9c7ab075c43e983fdeb9af80447caa501337Romain Guy        int[] getConfig(boolean dirtyRegions) {
1348e91a9c7ab075c43e983fdeb9af80447caa501337Romain Guy            return new int[] {
1349484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                    EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
1350484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                    EGL_RED_SIZE, 8,
1351484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                    EGL_GREEN_SIZE, 8,
1352484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                    EGL_BLUE_SIZE, 8,
1353484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                    EGL_ALPHA_SIZE, 8,
1354484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                    EGL_DEPTH_SIZE, 0,
1355530041d3191ce817832a0108514617768e43cda6Romain Guy                    EGL_STENCIL_SIZE, GLES20Canvas.getStencilSize(),
1356484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                    EGL_SURFACE_TYPE, EGL_WINDOW_BIT |
135708645eb0f4a8d73b2b2f26d3232f45cf459a27bcRomain Guy                            (dirtyRegions ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0),
1358484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                    EGL_NONE
1359e91a9c7ab075c43e983fdeb9af80447caa501337Romain Guy            };
1360e91a9c7ab075c43e983fdeb9af80447caa501337Romain Guy        }
13618ff6b9ebeeb24a6161ec6098e6bfdf8790ee5695Romain Guy
13628ff6b9ebeeb24a6161ec6098e6bfdf8790ee5695Romain Guy        @Override
13638ff6b9ebeeb24a6161ec6098e6bfdf8790ee5695Romain Guy        void initCaches() {
13648ff6b9ebeeb24a6161ec6098e6bfdf8790ee5695Romain Guy            GLES20Canvas.initCaches();
13658ff6b9ebeeb24a6161ec6098e6bfdf8790ee5695Romain Guy        }
1366e91a9c7ab075c43e983fdeb9af80447caa501337Romain Guy
1367b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy        @Override
1368b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy        boolean canDraw() {
1369b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy            return super.canDraw() && mGlCanvas != null;
1370b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy        }
1371e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
1372e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        @Override
137344b2fe3fc114ee5f7273c6b0fee2cc999bf244a2Chet Haase        int onPreDraw(Rect dirty) {
137444b2fe3fc114ee5f7273c6b0fee2cc999bf244a2Chet Haase            return mGlCanvas.onPreDraw(dirty);
1375e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        }
1376e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
1377b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy        @Override
1378b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy        void onPostDraw() {
1379b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy            mGlCanvas.onPostDraw();
1380b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy        }
1381b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy
1382b051e895ccb696604349c6c5efe7c4747e1d1ab6Romain Guy        @Override
138367f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy        void destroy(boolean full) {
1384b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy            try {
1385b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy                super.destroy(full);
1386b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy            } finally {
1387b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy                if (full && mGlCanvas != null) {
1388b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy                    mGlCanvas = null;
1389b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy                }
139067f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy            }
139167f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy        }
139267f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy
139367f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy        @Override
13949ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy        void setup(int width, int height) {
13959ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy            super.setup(width, height);
13969ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy            if (mVsyncDisabled) {
1397244ada1d35419b7be9de0fc833bb03955b725ffaRomain Guy                disableVsync();
13989ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy            }
13999ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy        }
14009ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy
14019ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy        @Override
140213631f3da855f200a151e7837ed9f6b079622b58Romain Guy        public DisplayList createDisplayList(String name) {
140313631f3da855f200a151e7837ed9f6b079622b58Romain Guy            return new GLES20DisplayList(name);
1404b051e895ccb696604349c6c5efe7c4747e1d1ab6Romain Guy        }
1405aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy
1406aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy        @Override
1407a9489274d67b540804aafb587a226f7c2ae4464dRomain Guy        HardwareLayer createHardwareLayer(boolean isOpaque) {
1408a9489274d67b540804aafb587a226f7c2ae4464dRomain Guy            return new GLES20TextureLayer(isOpaque);
1409aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy        }
1410aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy
14116c319ca1275c8db892c39b48fc54864c949f9171Romain Guy        @Override
14126c319ca1275c8db892c39b48fc54864c949f9171Romain Guy        HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque) {
1413aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy            return new GLES20RenderLayer(width, height, isOpaque);
1414aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy        }
1415aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy
1416aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy        @Override
1417e5e0c50f7dfaccc220725c5595080e921ffda1e4Romain Guy        SurfaceTexture createSurfaceTexture(HardwareLayer layer) {
1418aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy            return ((GLES20TextureLayer) layer).getSurfaceTexture();
1419aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy        }
1420aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy
14216d7475d666baefaa3ba9f0dcee25238739454241Romain Guy        @Override
14222af3524beb75150d347accc925022daa53b4a789Jamie Gennis        void setSurfaceTexture(HardwareLayer layer, SurfaceTexture surfaceTexture) {
14232af3524beb75150d347accc925022daa53b4a789Jamie Gennis            ((GLES20TextureLayer) layer).setSurfaceTexture(surfaceTexture);
14242af3524beb75150d347accc925022daa53b4a789Jamie Gennis        }
14252af3524beb75150d347accc925022daa53b4a789Jamie Gennis
14262af3524beb75150d347accc925022daa53b4a789Jamie Gennis        @Override
14276d7475d666baefaa3ba9f0dcee25238739454241Romain Guy        void destroyLayers(View view) {
142816260e73f6c1c9dc94acf0d328a3c564426b8711Romain Guy            if (view != null && isEnabled() && checkCurrent() != SURFACE_STATE_ERROR) {
14296d7475d666baefaa3ba9f0dcee25238739454241Romain Guy                destroyHardwareLayer(view);
14306d7475d666baefaa3ba9f0dcee25238739454241Romain Guy                GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
14316d7475d666baefaa3ba9f0dcee25238739454241Romain Guy            }
14326d7475d666baefaa3ba9f0dcee25238739454241Romain Guy        }
14336d7475d666baefaa3ba9f0dcee25238739454241Romain Guy
143431f2c2e94656530fbf6282803e62edb47e9a894dRomain Guy        private static void destroyHardwareLayer(View view) {
1435a998dff5d49a423aaf7097aa8f96bf5bdc681d25Romain Guy            view.destroyLayer(true);
143631f2c2e94656530fbf6282803e62edb47e9a894dRomain Guy
14376d7475d666baefaa3ba9f0dcee25238739454241Romain Guy            if (view instanceof ViewGroup) {
14386d7475d666baefaa3ba9f0dcee25238739454241Romain Guy                ViewGroup group = (ViewGroup) view;
14396d7475d666baefaa3ba9f0dcee25238739454241Romain Guy
14406d7475d666baefaa3ba9f0dcee25238739454241Romain Guy                int count = group.getChildCount();
14416d7475d666baefaa3ba9f0dcee25238739454241Romain Guy                for (int i = 0; i < count; i++) {
14426d7475d666baefaa3ba9f0dcee25238739454241Romain Guy                    destroyHardwareLayer(group.getChildAt(i));
14436d7475d666baefaa3ba9f0dcee25238739454241Romain Guy                }
14446d7475d666baefaa3ba9f0dcee25238739454241Romain Guy            }
14456d7475d666baefaa3ba9f0dcee25238739454241Romain Guy        }
1446244ada1d35419b7be9de0fc833bb03955b725ffaRomain Guy
144731f2c2e94656530fbf6282803e62edb47e9a894dRomain Guy        @Override
14481ac4765e959c79101f64b1279887ed469334c268Romain Guy        boolean safelyRun(Runnable action) {
14491ac4765e959c79101f64b1279887ed469334c268Romain Guy            boolean needsContext = true;
14501ac4765e959c79101f64b1279887ed469334c268Romain Guy            if (isEnabled() && checkCurrent() != SURFACE_STATE_ERROR) needsContext = false;
14511ac4765e959c79101f64b1279887ed469334c268Romain Guy
14521ac4765e959c79101f64b1279887ed469334c268Romain Guy            if (needsContext) {
14531ac4765e959c79101f64b1279887ed469334c268Romain Guy                Gl20RendererEglContext managedContext =
14541ac4765e959c79101f64b1279887ed469334c268Romain Guy                        (Gl20RendererEglContext) sEglContextStorage.get();
14551ac4765e959c79101f64b1279887ed469334c268Romain Guy                if (managedContext == null) return false;
14561ac4765e959c79101f64b1279887ed469334c268Romain Guy                usePbufferSurface(managedContext.getContext());
14571ac4765e959c79101f64b1279887ed469334c268Romain Guy            }
14580872b370422eb1f9007b4717b8796543873e6390Jesse Hall
14591ac4765e959c79101f64b1279887ed469334c268Romain Guy            try {
14601ac4765e959c79101f64b1279887ed469334c268Romain Guy                action.run();
14611ac4765e959c79101f64b1279887ed469334c268Romain Guy            } finally {
14620872b370422eb1f9007b4717b8796543873e6390Jesse Hall                if (needsContext) {
14630872b370422eb1f9007b4717b8796543873e6390Jesse Hall                    sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE,
14640872b370422eb1f9007b4717b8796543873e6390Jesse Hall                            EGL_NO_SURFACE, EGL_NO_CONTEXT);
14650872b370422eb1f9007b4717b8796543873e6390Jesse Hall                }
146631f2c2e94656530fbf6282803e62edb47e9a894dRomain Guy            }
14671ac4765e959c79101f64b1279887ed469334c268Romain Guy
14681ac4765e959c79101f64b1279887ed469334c268Romain Guy            return true;
14691ac4765e959c79101f64b1279887ed469334c268Romain Guy        }
14701ac4765e959c79101f64b1279887ed469334c268Romain Guy
14711ac4765e959c79101f64b1279887ed469334c268Romain Guy        @Override
14721ac4765e959c79101f64b1279887ed469334c268Romain Guy        void destroyHardwareResources(final View view) {
14731ac4765e959c79101f64b1279887ed469334c268Romain Guy            if (view != null) {
14741ac4765e959c79101f64b1279887ed469334c268Romain Guy                safelyRun(new Runnable() {
14751ac4765e959c79101f64b1279887ed469334c268Romain Guy                    @Override
14761ac4765e959c79101f64b1279887ed469334c268Romain Guy                    public void run() {
14771ac4765e959c79101f64b1279887ed469334c268Romain Guy                        destroyResources(view);
14781ac4765e959c79101f64b1279887ed469334c268Romain Guy                        GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
14791ac4765e959c79101f64b1279887ed469334c268Romain Guy                    }
14801ac4765e959c79101f64b1279887ed469334c268Romain Guy                });
14811ac4765e959c79101f64b1279887ed469334c268Romain Guy            }
148231f2c2e94656530fbf6282803e62edb47e9a894dRomain Guy        }
1483244ada1d35419b7be9de0fc833bb03955b725ffaRomain Guy
148431f2c2e94656530fbf6282803e62edb47e9a894dRomain Guy        private static void destroyResources(View view) {
148531f2c2e94656530fbf6282803e62edb47e9a894dRomain Guy            view.destroyHardwareResources();
148631f2c2e94656530fbf6282803e62edb47e9a894dRomain Guy
148731f2c2e94656530fbf6282803e62edb47e9a894dRomain Guy            if (view instanceof ViewGroup) {
148831f2c2e94656530fbf6282803e62edb47e9a894dRomain Guy                ViewGroup group = (ViewGroup) view;
148931f2c2e94656530fbf6282803e62edb47e9a894dRomain Guy
149031f2c2e94656530fbf6282803e62edb47e9a894dRomain Guy                int count = group.getChildCount();
149131f2c2e94656530fbf6282803e62edb47e9a894dRomain Guy                for (int i = 0; i < count; i++) {
149231f2c2e94656530fbf6282803e62edb47e9a894dRomain Guy                    destroyResources(group.getChildAt(i));
149331f2c2e94656530fbf6282803e62edb47e9a894dRomain Guy                }
149431f2c2e94656530fbf6282803e62edb47e9a894dRomain Guy            }
149531f2c2e94656530fbf6282803e62edb47e9a894dRomain Guy        }
14966d7475d666baefaa3ba9f0dcee25238739454241Romain Guy
14976d7475d666baefaa3ba9f0dcee25238739454241Romain Guy        static HardwareRenderer create(boolean translucent) {
14986d7475d666baefaa3ba9f0dcee25238739454241Romain Guy            if (GLES20Canvas.isAvailable()) {
14996d7475d666baefaa3ba9f0dcee25238739454241Romain Guy                return new Gl20Renderer(translucent);
15006d7475d666baefaa3ba9f0dcee25238739454241Romain Guy            }
15016d7475d666baefaa3ba9f0dcee25238739454241Romain Guy            return null;
15026d7475d666baefaa3ba9f0dcee25238739454241Romain Guy        }
15036d7475d666baefaa3ba9f0dcee25238739454241Romain Guy
150419f86e831ee0629b24385b0bb51d27ff91961dd2Romain Guy        static void startTrimMemory(int level) {
1505912a7b32d0c59ba38265c5dd6ff84ce93f909a7fRomain Guy            if (sEgl == null || sEglConfig == null) return;
1506912a7b32d0c59ba38265c5dd6ff84ce93f909a7fRomain Guy
15075d6999e1ca457948e06792ea6259ffa947c9fa81Romain Guy            Gl20RendererEglContext managedContext =
15085d6999e1ca457948e06792ea6259ffa947c9fa81Romain Guy                    (Gl20RendererEglContext) sEglContextStorage.get();
1509912a7b32d0c59ba38265c5dd6ff84ce93f909a7fRomain Guy            // We do not have OpenGL objects
1510717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn            if (managedContext == null) {
1511912a7b32d0c59ba38265c5dd6ff84ce93f909a7fRomain Guy                return;
1512912a7b32d0c59ba38265c5dd6ff84ce93f909a7fRomain Guy            } else {
1513717a25dc2a411edb548859cd6870363346c71b01Dianne Hackborn                usePbufferSurface(managedContext.getContext());
15142d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy            }
1515912a7b32d0c59ba38265c5dd6ff84ce93f909a7fRomain Guy
151627ff913d56de8400083a13fc572e2812b32c890cDianne Hackborn            if (level >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE) {
151727ff913d56de8400083a13fc572e2812b32c890cDianne Hackborn                GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_FULL);
151827ff913d56de8400083a13fc572e2812b32c890cDianne Hackborn            } else if (level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
151927ff913d56de8400083a13fc572e2812b32c890cDianne Hackborn                GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_MODERATE);
1520bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy            }
152119f86e831ee0629b24385b0bb51d27ff91961dd2Romain Guy        }
15220872b370422eb1f9007b4717b8796543873e6390Jesse Hall
152319f86e831ee0629b24385b0bb51d27ff91961dd2Romain Guy        static void endTrimMemory() {
152419f86e831ee0629b24385b0bb51d27ff91961dd2Romain Guy            if (sEgl != null && sEglDisplay != null) {
152519f86e831ee0629b24385b0bb51d27ff91961dd2Romain Guy                sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
152619f86e831ee0629b24385b0bb51d27ff91961dd2Romain Guy            }
1527bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy        }
15288ff6b9ebeeb24a6161ec6098e6bfdf8790ee5695Romain Guy
15298ff6b9ebeeb24a6161ec6098e6bfdf8790ee5695Romain Guy        private static void usePbufferSurface(EGLContext eglContext) {
15308ff6b9ebeeb24a6161ec6098e6bfdf8790ee5695Romain Guy            synchronized (sPbufferLock) {
15318ff6b9ebeeb24a6161ec6098e6bfdf8790ee5695Romain Guy                // Create a temporary 1x1 pbuffer so we have a context
15328ff6b9ebeeb24a6161ec6098e6bfdf8790ee5695Romain Guy                // to clear our OpenGL objects
15338ff6b9ebeeb24a6161ec6098e6bfdf8790ee5695Romain Guy                if (sPbuffer == null) {
15348ff6b9ebeeb24a6161ec6098e6bfdf8790ee5695Romain Guy                    sPbuffer = sEgl.eglCreatePbufferSurface(sEglDisplay, sEglConfig, new int[] {
15358ff6b9ebeeb24a6161ec6098e6bfdf8790ee5695Romain Guy                            EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE
15368ff6b9ebeeb24a6161ec6098e6bfdf8790ee5695Romain Guy                    });
15378ff6b9ebeeb24a6161ec6098e6bfdf8790ee5695Romain Guy                }
15388ff6b9ebeeb24a6161ec6098e6bfdf8790ee5695Romain Guy            }
15398ff6b9ebeeb24a6161ec6098e6bfdf8790ee5695Romain Guy            sEgl.eglMakeCurrent(sEglDisplay, sPbuffer, sPbuffer, eglContext);
15408ff6b9ebeeb24a6161ec6098e6bfdf8790ee5695Romain Guy        }
15412d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    }
15422d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy}
1543