HardwareRenderer.java revision 912a7b32d0c59ba38265c5dd6ff84ce93f909a7f
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
20bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guyimport android.content.ComponentCallbacks;
217d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guyimport android.graphics.Paint;
227d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guyimport android.graphics.Rect;
23aa6c24c21c727a196451332448d4e3b11a80be69Romain Guyimport android.graphics.SurfaceTexture;
2402ccac69fd1c0a03c24c5f3ace0ad4bed337b1fdRomain Guyimport android.os.SystemClock;
2502ccac69fd1c0a03c24c5f3ace0ad4bed337b1fdRomain Guyimport android.os.SystemProperties;
26e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guyimport android.util.Log;
272d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
282d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guyimport javax.microedition.khronos.egl.EGL10;
292d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guyimport javax.microedition.khronos.egl.EGL11;
302d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guyimport javax.microedition.khronos.egl.EGLConfig;
312d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guyimport javax.microedition.khronos.egl.EGLContext;
322d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guyimport javax.microedition.khronos.egl.EGLDisplay;
332d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guyimport javax.microedition.khronos.egl.EGLSurface;
34e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guyimport javax.microedition.khronos.opengles.GL;
352d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
36484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guyimport static javax.microedition.khronos.egl.EGL10.*;
37484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy
382d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy/**
39c6cc0f8c19d9eccf408a443fa2bf668af261dcd0Joe Onorato * Interface for rendering a ViewAncestor using hardware acceleration.
402d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy *
412d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy * @hide
422d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy */
4361c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guypublic abstract class HardwareRenderer {
444f6aff386045000c2c03b903c7109cb42092b7eaRomain Guy    static final String LOG_TAG = "HardwareRenderer";
45fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy
465233920a216302b4aa03b100c32e8b3efe33cbc6Romain Guy    /**
477d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy     * Turn on to only refresh the parts of the screen that need updating.
48069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy     * When turned on the property defined by {@link #RENDER_DIRTY_REGIONS_PROPERTY}
49069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy     * must also have the value "true".
507d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy     */
517d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    public static final boolean RENDER_DIRTY_REGIONS = true;
527d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy
537d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    /**
54069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy     * System property used to enable or disable dirty regions invalidation.
55069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy     * This property is only queried if {@link #RENDER_DIRTY_REGIONS} is true.
56069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy     * The default value of this property is assumed to be true.
57069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy     *
58069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy     * Possible values:
59069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy     * "true", to enable partial invalidates
60069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy     * "false", to disable partial invalidates
61069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy     */
62069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy    static final String RENDER_DIRTY_REGIONS_PROPERTY = "hwui.render_dirty_regions";
639ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy
649ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy    /**
659ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy     * System property used to enable or disable vsync.
669ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy     * The default value of this property is assumed to be false.
679ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy     *
689ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy     * Possible values:
699ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy     * "true", to disable vsync
709ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy     * "false", to enable vsync
719ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy     */
729ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy    static final String DISABLE_VSYNC_PROPERTY = "hwui.disable_vsync";
73069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy
74069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy    /**
75484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy     * System property used to debug EGL configuration choice.
76484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy     *
77484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy     * Possible values:
78484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy     * "choice", print the chosen configuration only
79484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy     * "all", print all possible configurations
80484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy     */
81484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy    static final String PRINT_CONFIG_PROPERTY = "hwui.print_config";
82484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy
83484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy    /**
847d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy     * Turn on to draw dirty regions every other frame.
857d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy     */
867d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    private static final boolean DEBUG_DIRTY_REGION = false;
877d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy
887d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    /**
895233920a216302b4aa03b100c32e8b3efe33cbc6Romain Guy     * A process can set this flag to false to prevent the use of hardware
905233920a216302b4aa03b100c32e8b3efe33cbc6Romain Guy     * rendering.
915233920a216302b4aa03b100c32e8b3efe33cbc6Romain Guy     *
925233920a216302b4aa03b100c32e8b3efe33cbc6Romain Guy     * @hide
935233920a216302b4aa03b100c32e8b3efe33cbc6Romain Guy     */
945233920a216302b4aa03b100c32e8b3efe33cbc6Romain Guy    public static boolean sRendererDisabled = false;
955233920a216302b4aa03b100c32e8b3efe33cbc6Romain Guy
962d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    private boolean mEnabled;
972d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    private boolean mRequested = true;
982d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
992d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    /**
10067f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy     * Invoke this method to disable hardware rendering in the current process.
1015233920a216302b4aa03b100c32e8b3efe33cbc6Romain Guy     *
1025233920a216302b4aa03b100c32e8b3efe33cbc6Romain Guy     * @hide
1035233920a216302b4aa03b100c32e8b3efe33cbc6Romain Guy     */
1045233920a216302b4aa03b100c32e8b3efe33cbc6Romain Guy    public static void disable() {
1055233920a216302b4aa03b100c32e8b3efe33cbc6Romain Guy        sRendererDisabled = true;
1065233920a216302b4aa03b100c32e8b3efe33cbc6Romain Guy    }
1075233920a216302b4aa03b100c32e8b3efe33cbc6Romain Guy
1085233920a216302b4aa03b100c32e8b3efe33cbc6Romain Guy    /**
10961c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy     * Indicates whether hardware acceleration is available under any form for
11061c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy     * the view hierarchy.
11161c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy     *
11261c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy     * @return True if the view hierarchy can potentially be hardware accelerated,
11361c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy     *         false otherwise
11461c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy     */
11561c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy    public static boolean isAvailable() {
11661c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        return GLES20Canvas.isAvailable();
11761c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy    }
11861c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy
11961c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy    /**
1202d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * Destroys the hardware rendering context.
1214caa4ed120a86e855d4d3b6b455c6fb9ca22e365Romain Guy     *
1224caa4ed120a86e855d4d3b6b455c6fb9ca22e365Romain Guy     * @param full If true, destroys all associated resources.
1232d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     */
1244caa4ed120a86e855d4d3b6b455c6fb9ca22e365Romain Guy    abstract void destroy(boolean full);
1252d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
1262d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    /**
1272d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * Initializes the hardware renderer for the specified surface.
1282d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     *
1292d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * @param holder The holder for the surface to hardware accelerate.
1302d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     *
1312d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * @return True if the initialization was successful, false otherwise.
1322d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     */
133648251710162cdaf7371012a1cbb79b9bc5bc0e4Dianne Hackborn    abstract boolean initialize(SurfaceHolder holder) throws Surface.OutOfResourcesException;
1342a83f001fdb189f945e82e81e717ba204824b112Romain Guy
1352a83f001fdb189f945e82e81e717ba204824b112Romain Guy    /**
1362a83f001fdb189f945e82e81e717ba204824b112Romain Guy     * Updates the hardware renderer for the specified surface.
1372a83f001fdb189f945e82e81e717ba204824b112Romain Guy     *
1382a83f001fdb189f945e82e81e717ba204824b112Romain Guy     * @param holder The holder for the surface to hardware accelerate.
1392a83f001fdb189f945e82e81e717ba204824b112Romain Guy     */
140648251710162cdaf7371012a1cbb79b9bc5bc0e4Dianne Hackborn    abstract void updateSurface(SurfaceHolder holder) throws Surface.OutOfResourcesException;
1412d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
1422d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    /**
143039857520b1a03a52051b966d87d587225bdfcc3Romain Guy     * This method should be invoked whenever the current hardware renderer
144039857520b1a03a52051b966d87d587225bdfcc3Romain Guy     * context should be reset.
1457e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy     */
146039857520b1a03a52051b966d87d587225bdfcc3Romain Guy    abstract void invalidate();
147039857520b1a03a52051b966d87d587225bdfcc3Romain Guy
148039857520b1a03a52051b966d87d587225bdfcc3Romain Guy    /**
149039857520b1a03a52051b966d87d587225bdfcc3Romain Guy     * This method should be invoked to ensure the hardware renderer is in
150039857520b1a03a52051b966d87d587225bdfcc3Romain Guy     * valid state (for instance, to ensure the correct EGL context is bound
151039857520b1a03a52051b966d87d587225bdfcc3Romain Guy     * to the current thread.)
152039857520b1a03a52051b966d87d587225bdfcc3Romain Guy     *
153039857520b1a03a52051b966d87d587225bdfcc3Romain Guy     * @return true if the renderer is now valid, false otherwise
154039857520b1a03a52051b966d87d587225bdfcc3Romain Guy     */
155039857520b1a03a52051b966d87d587225bdfcc3Romain Guy    abstract boolean validate();
1567e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy
1577e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy    /**
1587e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy     * Setup the hardware renderer for drawing. This is called whenever the
1597e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy     * size of the target surface changes or when the surface is first created.
1602d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     *
1612d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * @param width Width of the drawing surface.
1622d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * @param height Height of the drawing surface.
1632d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     */
164fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    abstract void setup(int width, int height);
1652d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
166069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy    /**
167069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy     * Interface used to receive callbacks whenever a view is drawn by
168069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy     * a hardware renderer instance.
169069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy     */
1700f761d6b8f5d5a607c87dbcdca6fe0ec7911970eDianne Hackborn    interface HardwareDrawCallbacks {
171069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy        /**
172069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy         * Invoked before a view is drawn by a hardware renderer.
173069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy         *
174069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy         * @param canvas The Canvas used to render the view.
175069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy         */
1767d70fbf0b5672bada8b25f065bc292796c3d4812Romain Guy        void onHardwarePreDraw(HardwareCanvas canvas);
177069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy
178069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy        /**
179069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy         * Invoked after a view is drawn by a hardware renderer.
180069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy         *
181069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy         * @param canvas The Canvas used to render the view.
182069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy         */
1837d70fbf0b5672bada8b25f065bc292796c3d4812Romain Guy        void onHardwarePostDraw(HardwareCanvas canvas);
1840f761d6b8f5d5a607c87dbcdca6fe0ec7911970eDianne Hackborn    }
1850f761d6b8f5d5a607c87dbcdca6fe0ec7911970eDianne Hackborn
1862d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    /**
1872d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * Draws the specified view.
1887d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy     *
1892d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * @param view The view to draw.
1902d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * @param attachInfo AttachInfo tied to the specified view.
1917d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy     * @param callbacks Callbacks invoked when drawing happens.
1927d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy     * @param dirty The dirty rectangle to update, can be null.
1932d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     */
1947d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    abstract void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks,
1957d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy            Rect dirty);
1962d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
1972d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    /**
19853ca03d9a3a6a95286302802173c4820b16328ceRomain Guy     * Creates a new display list that can be used to record batches of
19953ca03d9a3a6a95286302802173c4820b16328ceRomain Guy     * drawing operations.
200b051e895ccb696604349c6c5efe7c4747e1d1ab6Romain Guy     *
20153ca03d9a3a6a95286302802173c4820b16328ceRomain Guy     * @return A new display list.
202b051e895ccb696604349c6c5efe7c4747e1d1ab6Romain Guy     */
203162a0217563f4665da6eb183dfce0fef740f641fJeff Brown    abstract DisplayList createDisplayList();
204b051e895ccb696604349c6c5efe7c4747e1d1ab6Romain Guy
205b051e895ccb696604349c6c5efe7c4747e1d1ab6Romain Guy    /**
206aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy     * Creates a new hardware layer. A hardware layer built by calling this
207aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy     * method will be treated as a texture layer, instead of as a render target.
208aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy     *
209a9489274d67b540804aafb587a226f7c2ae4464dRomain Guy     * @param isOpaque Whether the layer should be opaque or not
210a9489274d67b540804aafb587a226f7c2ae4464dRomain Guy     *
211aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy     * @return A hardware layer
212aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy     */
213a9489274d67b540804aafb587a226f7c2ae4464dRomain Guy    abstract HardwareLayer createHardwareLayer(boolean isOpaque);
214aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy
215aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy    /**
2166c319ca1275c8db892c39b48fc54864c949f9171Romain Guy     * Creates a new hardware layer.
2176c319ca1275c8db892c39b48fc54864c949f9171Romain Guy     *
2186c319ca1275c8db892c39b48fc54864c949f9171Romain Guy     * @param width The minimum width of the layer
2196c319ca1275c8db892c39b48fc54864c949f9171Romain Guy     * @param height The minimum height of the layer
2206c319ca1275c8db892c39b48fc54864c949f9171Romain Guy     * @param isOpaque Whether the layer should be opaque or not
2216c319ca1275c8db892c39b48fc54864c949f9171Romain Guy     *
2226c319ca1275c8db892c39b48fc54864c949f9171Romain Guy     * @return A hardware layer
2236c319ca1275c8db892c39b48fc54864c949f9171Romain Guy     */
2246c319ca1275c8db892c39b48fc54864c949f9171Romain Guy    abstract HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque);
225aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy
226aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy    /**
227aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy     * Creates a new {@link SurfaceTexture} that can be used to render into the
228aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy     * specified hardware layer.
229aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy     *
230aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy     *
231aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy     * @param layer The layer to render into using a {@link android.graphics.SurfaceTexture}
232aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy     *
233aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy     * @return A {@link SurfaceTexture}
234aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy     */
235e5e0c50f7dfaccc220725c5595080e921ffda1e4Romain Guy    abstract SurfaceTexture createSurfaceTexture(HardwareLayer layer);
236aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy
237aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy    /**
2382d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * Initializes the hardware renderer for the specified surface and setup the
239c6cc0f8c19d9eccf408a443fa2bf668af261dcd0Joe Onorato     * renderer for drawing, if needed. This is invoked when the ViewAncestor has
2402d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * potentially lost the hardware renderer. The hardware renderer should be
2412d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * reinitialized and setup when the render {@link #isRequested()} and
2422d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * {@link #isEnabled()}.
2432d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     *
2442d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * @param width The width of the drawing surface.
2452d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * @param height The height of the drawing surface.
2462d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * @param attachInfo The
2472d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * @param holder
2482d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     */
2492d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    void initializeIfNeeded(int width, int height, View.AttachInfo attachInfo,
250648251710162cdaf7371012a1cbb79b9bc5bc0e4Dianne Hackborn            SurfaceHolder holder) throws Surface.OutOfResourcesException {
2512d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        if (isRequested()) {
2522d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy            // We lost the gl context, so recreate it.
2532d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy            if (!isEnabled()) {
2542d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy                if (initialize(holder)) {
255fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy                    setup(width, height);
2562d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy                }
2572d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy            }
2582d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        }
2592d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    }
2602d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
2612d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    /**
2622d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * Creates a hardware renderer using OpenGL.
2632d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     *
2642d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * @param glVersion The version of OpenGL to use (1 for OpenGL 1, 11 for OpenGL 1.1, etc.)
265e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy     * @param translucent True if the surface is translucent, false otherwise
2662d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     *
2672d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * @return A hardware renderer backed by OpenGL.
2682d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     */
269e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    static HardwareRenderer createGlRenderer(int glVersion, boolean translucent) {
2702d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        switch (glVersion) {
271e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            case 2:
272163935113919a184122b8b3bd672ef08c8df65dcRomain Guy                return Gl20Renderer.create(translucent);
2732d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        }
2742d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        throw new IllegalArgumentException("Unknown GL version: " + glVersion);
2752d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    }
2762d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
2772d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    /**
278bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy     * Invoke this method when the system is running out of memory. This
279bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy     * method will attempt to recover as much memory as possible, based on
280bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy     * the specified hint.
281bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy     *
282bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy     * @param level Hint about the amount of memory that should be trimmed,
283bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy     *              see {@link android.content.ComponentCallbacks}
284bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy     */
285bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy    static void trimMemory(int level) {
286912a7b32d0c59ba38265c5dd6ff84ce93f909a7fRomain Guy        Gl20Renderer.trimMemory(level);
287bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy    }
288bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy
289bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy    /**
2902d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * Indicates whether hardware acceleration is currently enabled.
2912d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     *
2922d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * @return True if hardware acceleration is in use, false otherwise.
2932d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     */
2942d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    boolean isEnabled() {
2952d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        return mEnabled;
2962d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    }
2972d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
2982d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    /**
2992d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * Indicates whether hardware acceleration is currently enabled.
3002d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     *
3012d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * @param enabled True if the hardware renderer is in use, false otherwise.
3022d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     */
3032d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    void setEnabled(boolean enabled) {
3042d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        mEnabled = enabled;
3052d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    }
3062d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
3072d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    /**
3082d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * Indicates whether hardware acceleration is currently request but not
3092d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * necessarily enabled yet.
3102d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     *
3112d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * @return True if requested, false otherwise.
3122d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     */
3132d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    boolean isRequested() {
3142d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        return mRequested;
3152d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    }
3162d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
3172d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    /**
3189745fae73b584f3e9a9c304098ed9b11f506e93bRomain Guy     * Indicates whether hardware acceleration is currently requested but not
3192d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * necessarily enabled yet.
3202d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     *
3212d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * @return True to request hardware acceleration, false otherwise.
3222d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     */
3232d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    void setRequested(boolean requested) {
3242d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        mRequested = requested;
3252d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    }
3262d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
3272d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    @SuppressWarnings({"deprecation"})
328e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy    static abstract class GlRenderer extends HardwareRenderer {
329aaceeb0c5be11121a81e44b9633c06fc5c0fcd4dRomain Guy        // These values are not exposed in our EGL APIs
330e91a9c7ab075c43e983fdeb9af80447caa501337Romain Guy        static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
331e91a9c7ab075c43e983fdeb9af80447caa501337Romain Guy        static final int EGL_OPENGL_ES2_BIT = 4;
3327e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy        static final int EGL_SURFACE_TYPE = 0x3033;
3337e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy        static final int EGL_SWAP_BEHAVIOR_PRESERVED_BIT = 0x0400;
334e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
335d88f54c5c4ce59585b8b9e6009836f14c00be743Romain Guy        private static final int SURFACE_STATE_ERROR = 0;
336d88f54c5c4ce59585b8b9e6009836f14c00be743Romain Guy        private static final int SURFACE_STATE_SUCCESS = 1;
337d88f54c5c4ce59585b8b9e6009836f14c00be743Romain Guy        private static final int SURFACE_STATE_UPDATED = 2;
338d88f54c5c4ce59585b8b9e6009836f14c00be743Romain Guy
339fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        static EGL10 sEgl;
340fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        static EGLDisplay sEglDisplay;
341fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        static EGLConfig sEglConfig;
342566b3efb25299d2a9c8ae827522802bad965426aRomain Guy        static final Object[] sEglLock = new Object[0];
343e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
344566b3efb25299d2a9c8ae827522802bad965426aRomain Guy        static final ThreadLocal<EGLContext> sEglContextStorage = new ThreadLocal<EGLContext>();
345566b3efb25299d2a9c8ae827522802bad965426aRomain Guy
346566b3efb25299d2a9c8ae827522802bad965426aRomain Guy        EGLContext mEglContext;
347566b3efb25299d2a9c8ae827522802bad965426aRomain Guy        Thread mEglThread;
348fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy
349fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        EGLSurface mEglSurface;
350fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy
351e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        GL mGl;
35267f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy        HardwareCanvas mCanvas;
3537d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy        int mFrameCount;
3547d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy        Paint mDebugPaint;
3557d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy
3567e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy        static boolean sDirtyRegions;
3577e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy        static final boolean sDirtyRegionsRequested;
3587e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy        static {
3597e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy            String dirtyProperty = SystemProperties.get(RENDER_DIRTY_REGIONS_PROPERTY, "true");
3607e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy            //noinspection PointlessBooleanExpression,ConstantConditions
3617e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy            sDirtyRegions = RENDER_DIRTY_REGIONS && "true".equalsIgnoreCase(dirtyProperty);
3627e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy            sDirtyRegionsRequested = sDirtyRegions;
3637e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy        }
3647e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy
3657e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy        boolean mDirtyRegionsEnabled;
3669ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy        final boolean mVsyncDisabled;
3672d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
368e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        final int mGlVersion;
369e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        final boolean mTranslucent;
3702d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
371fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        private boolean mDestroyed;
372566b3efb25299d2a9c8ae827522802bad965426aRomain Guy
373cabfcc1364eb7e4de0b15b3574fba45027b45cfcRomain Guy        private final Rect mRedrawClip = new Rect();
374fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy
375e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        GlRenderer(int glVersion, boolean translucent) {
376e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            mGlVersion = glVersion;
377e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            mTranslucent = translucent;
3789ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy
3799ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy            final String vsyncProperty = SystemProperties.get(DISABLE_VSYNC_PROPERTY, "false");
3809ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy            mVsyncDisabled = "true".equalsIgnoreCase(vsyncProperty);
3819ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy            if (mVsyncDisabled) {
3829ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy                Log.d(LOG_TAG, "Disabling v-sync");
3839ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy            }
3842d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        }
3852d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
386e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        /**
38702ccac69fd1c0a03c24c5f3ace0ad4bed337b1fdRomain Guy         * Indicates whether this renderer instance can track and update dirty regions.
38802ccac69fd1c0a03c24c5f3ace0ad4bed337b1fdRomain Guy         */
38902ccac69fd1c0a03c24c5f3ace0ad4bed337b1fdRomain Guy        boolean hasDirtyRegions() {
3907e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy            return mDirtyRegionsEnabled;
39102ccac69fd1c0a03c24c5f3ace0ad4bed337b1fdRomain Guy        }
39202ccac69fd1c0a03c24c5f3ace0ad4bed337b1fdRomain Guy
39302ccac69fd1c0a03c24c5f3ace0ad4bed337b1fdRomain Guy        /**
3945d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd         * Return a string for the EGL error code, or the hex representation
395d10cd5765a2b706fc174f16b951d6b0a5d3740d3Romain Guy         * if the error is unknown.
396d10cd5765a2b706fc174f16b951d6b0a5d3740d3Romain Guy         *
397d10cd5765a2b706fc174f16b951d6b0a5d3740d3Romain Guy         * @param error The EGL error to convert into a String.
398d10cd5765a2b706fc174f16b951d6b0a5d3740d3Romain Guy         *
399d10cd5765a2b706fc174f16b951d6b0a5d3740d3Romain Guy         * @return An error string correponding to the EGL error code.
4005d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd         */
4015d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd        static String getEGLErrorString(int error) {
4025d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd            switch (error) {
403484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                case EGL_SUCCESS:
4045d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                    return "EGL_SUCCESS";
405484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                case EGL_NOT_INITIALIZED:
4065d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                    return "EGL_NOT_INITIALIZED";
407484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                case EGL_BAD_ACCESS:
4085d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                    return "EGL_BAD_ACCESS";
409484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                case EGL_BAD_ALLOC:
4105d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                    return "EGL_BAD_ALLOC";
411484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                case EGL_BAD_ATTRIBUTE:
4125d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                    return "EGL_BAD_ATTRIBUTE";
413484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                case EGL_BAD_CONFIG:
4145d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                    return "EGL_BAD_CONFIG";
415484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                case EGL_BAD_CONTEXT:
4165d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                    return "EGL_BAD_CONTEXT";
417484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                case EGL_BAD_CURRENT_SURFACE:
4185d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                    return "EGL_BAD_CURRENT_SURFACE";
419484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                case EGL_BAD_DISPLAY:
4205d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                    return "EGL_BAD_DISPLAY";
421484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                case EGL_BAD_MATCH:
4225d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                    return "EGL_BAD_MATCH";
423484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                case EGL_BAD_NATIVE_PIXMAP:
4245d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                    return "EGL_BAD_NATIVE_PIXMAP";
425484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                case EGL_BAD_NATIVE_WINDOW:
4265d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                    return "EGL_BAD_NATIVE_WINDOW";
427484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                case EGL_BAD_PARAMETER:
4285d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                    return "EGL_BAD_PARAMETER";
429484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                case EGL_BAD_SURFACE:
4305d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                    return "EGL_BAD_SURFACE";
4315d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                case EGL11.EGL_CONTEXT_LOST:
4325d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                    return "EGL_CONTEXT_LOST";
4335d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                default:
4345d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                    return "0x" + Integer.toHexString(error);
4355d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd            }
4365d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd        }
4375d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd
4385d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd        /**
4394caa4ed120a86e855d4d3b6b455c6fb9ca22e365Romain Guy         * Checks for OpenGL errors. If an error has occured, {@link #destroy(boolean)}
440e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy         * is invoked and the requested flag is turned off. The error code is
441e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy         * also logged as a warning.
442e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy         */
443b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy        void checkEglErrors() {
444e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            if (isEnabled()) {
445fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy                int error = sEgl.eglGetError();
446484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                if (error != EGL_SUCCESS) {
447e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                    // something bad has happened revert to
448e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                    // normal rendering.
4499745fae73b584f3e9a9c304098ed9b11f506e93bRomain Guy                    fallback(error != EGL11.EGL_CONTEXT_LOST);
4505d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                    Log.w(LOG_TAG, "EGL error: " + getEGLErrorString(error));
451e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                }
4522d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy            }
4532d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        }
45467f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy
4559745fae73b584f3e9a9c304098ed9b11f506e93bRomain Guy        private void fallback(boolean fallback) {
4569745fae73b584f3e9a9c304098ed9b11f506e93bRomain Guy            destroy(true);
4579745fae73b584f3e9a9c304098ed9b11f506e93bRomain Guy            if (fallback) {
4589745fae73b584f3e9a9c304098ed9b11f506e93bRomain Guy                // we'll try again if it was context lost
4599745fae73b584f3e9a9c304098ed9b11f506e93bRomain Guy                setRequested(false);
4609745fae73b584f3e9a9c304098ed9b11f506e93bRomain Guy                Log.w(LOG_TAG, "Mountain View, we've had a problem here. "
4619745fae73b584f3e9a9c304098ed9b11f506e93bRomain Guy                        + "Switching back to software rendering.");
4629745fae73b584f3e9a9c304098ed9b11f506e93bRomain Guy            }
4639745fae73b584f3e9a9c304098ed9b11f506e93bRomain Guy        }
4649745fae73b584f3e9a9c304098ed9b11f506e93bRomain Guy
465e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        @Override
466648251710162cdaf7371012a1cbb79b9bc5bc0e4Dianne Hackborn        boolean initialize(SurfaceHolder holder) throws Surface.OutOfResourcesException {
467e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            if (isRequested() && !isEnabled()) {
468e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                initializeEgl();
469e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                mGl = createEglSurface(holder);
470fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy                mDestroyed = false;
4712d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
472e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                if (mGl != null) {
473fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy                    int err = sEgl.eglGetError();
474484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                    if (err != EGL_SUCCESS) {
4754caa4ed120a86e855d4d3b6b455c6fb9ca22e365Romain Guy                        destroy(true);
476e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                        setRequested(false);
477e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                    } else {
4784caa4ed120a86e855d4d3b6b455c6fb9ca22e365Romain Guy                        if (mCanvas == null) {
4794caa4ed120a86e855d4d3b6b455c6fb9ca22e365Romain Guy                            mCanvas = createCanvas();
480fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy                        }
481e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                        if (mCanvas != null) {
482e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                            setEnabled(true);
483e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                        } else {
484e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                            Log.w(LOG_TAG, "Hardware accelerated Canvas could not be created");
485e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                        }
486e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                    }
487e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
488e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                    return mCanvas != null;
489e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                }
490e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            }
491e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            return false;
492e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        }
4932a83f001fdb189f945e82e81e717ba204824b112Romain Guy
4942a83f001fdb189f945e82e81e717ba204824b112Romain Guy        @Override
495648251710162cdaf7371012a1cbb79b9bc5bc0e4Dianne Hackborn        void updateSurface(SurfaceHolder holder) throws Surface.OutOfResourcesException {
4962a83f001fdb189f945e82e81e717ba204824b112Romain Guy            if (isRequested() && isEnabled()) {
4972a83f001fdb189f945e82e81e717ba204824b112Romain Guy                createEglSurface(holder);
4982a83f001fdb189f945e82e81e717ba204824b112Romain Guy            }
4992a83f001fdb189f945e82e81e717ba204824b112Romain Guy        }
500e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
501fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        abstract GLES20Canvas createCanvas();
5022d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
50329d23ecfd8612ecd4a7b2140acd344934b73a558Romain Guy        abstract int[] getConfig(boolean dirtyRegions);
50429d23ecfd8612ecd4a7b2140acd344934b73a558Romain Guy
505e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        void initializeEgl() {
506566b3efb25299d2a9c8ae827522802bad965426aRomain Guy            synchronized (sEglLock) {
507566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                if (sEgl == null && sEglConfig == null) {
508566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                    sEgl = (EGL10) EGLContext.getEGL();
509566b3efb25299d2a9c8ae827522802bad965426aRomain Guy
510566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                    // Get to the default display.
511484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                    sEglDisplay = sEgl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
512566b3efb25299d2a9c8ae827522802bad965426aRomain Guy
513484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                    if (sEglDisplay == EGL_NO_DISPLAY) {
514566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                        throw new RuntimeException("eglGetDisplay failed "
515566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                                + getEGLErrorString(sEgl.eglGetError()));
516566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                    }
517566b3efb25299d2a9c8ae827522802bad965426aRomain Guy
518566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                    // We can now initialize EGL for that display
519566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                    int[] version = new int[2];
520566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                    if (!sEgl.eglInitialize(sEglDisplay, version)) {
521566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                        throw new RuntimeException("eglInitialize failed " +
522566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                                getEGLErrorString(sEgl.eglGetError()));
523566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                    }
524566b3efb25299d2a9c8ae827522802bad965426aRomain Guy
525e91a9c7ab075c43e983fdeb9af80447caa501337Romain Guy                    sEglConfig = chooseEglConfig();
526069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy                    if (sEglConfig == null) {
527566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                        // We tried to use EGL_SWAP_BEHAVIOR_PRESERVED_BIT, try again without
528566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                        if (sDirtyRegions) {
529566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                            sDirtyRegions = false;
530566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                            sEglConfig = chooseEglConfig();
531566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                            if (sEglConfig == null) {
532566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                                throw new RuntimeException("eglConfig not initialized");
533566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                            }
534566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                        } else {
535566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                            throw new RuntimeException("eglConfig not initialized");
536566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                        }
537069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy                    }
538069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy                }
539069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy            }
540566b3efb25299d2a9c8ae827522802bad965426aRomain Guy
541566b3efb25299d2a9c8ae827522802bad965426aRomain Guy            mEglContext = sEglContextStorage.get();
542566b3efb25299d2a9c8ae827522802bad965426aRomain Guy            mEglThread = Thread.currentThread();
543566b3efb25299d2a9c8ae827522802bad965426aRomain Guy
544566b3efb25299d2a9c8ae827522802bad965426aRomain Guy            if (mEglContext == null) {
545566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                mEglContext = createContext(sEgl, sEglDisplay, sEglConfig);
546566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                sEglContextStorage.set(mEglContext);
547566b3efb25299d2a9c8ae827522802bad965426aRomain Guy            }
548e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        }
549e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
550e91a9c7ab075c43e983fdeb9af80447caa501337Romain Guy        private EGLConfig chooseEglConfig() {
551e91a9c7ab075c43e983fdeb9af80447caa501337Romain Guy            EGLConfig[] configs = new EGLConfig[1];
552484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy            int[] configsCount = new int[1];
5537e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy            int[] configSpec = getConfig(sDirtyRegions);
554484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy
555484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy            // Debug
55629d23ecfd8612ecd4a7b2140acd344934b73a558Romain Guy            final String debug = SystemProperties.get(PRINT_CONFIG_PROPERTY, "");
557484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy            if ("all".equalsIgnoreCase(debug)) {
558484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                sEgl.eglChooseConfig(sEglDisplay, configSpec, null, 0, configsCount);
559484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy
560484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                EGLConfig[] debugConfigs = new EGLConfig[configsCount[0]];
561484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                sEgl.eglChooseConfig(sEglDisplay, configSpec, debugConfigs,
562484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                        configsCount[0], configsCount);
563484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy
564484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                for (EGLConfig config : debugConfigs) {
565484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                    printConfig(config);
566484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                }
567484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy            }
568484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy
569e91a9c7ab075c43e983fdeb9af80447caa501337Romain Guy            if (!sEgl.eglChooseConfig(sEglDisplay, configSpec, configs, 1, configsCount)) {
570e91a9c7ab075c43e983fdeb9af80447caa501337Romain Guy                throw new IllegalArgumentException("eglChooseConfig failed " +
571e91a9c7ab075c43e983fdeb9af80447caa501337Romain Guy                        getEGLErrorString(sEgl.eglGetError()));
572e91a9c7ab075c43e983fdeb9af80447caa501337Romain Guy            } else if (configsCount[0] > 0) {
573484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                if ("choice".equalsIgnoreCase(debug)) {
574484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                    printConfig(configs[0]);
575484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                }
576e91a9c7ab075c43e983fdeb9af80447caa501337Romain Guy                return configs[0];
577e91a9c7ab075c43e983fdeb9af80447caa501337Romain Guy            }
578484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy
579e91a9c7ab075c43e983fdeb9af80447caa501337Romain Guy            return null;
580e91a9c7ab075c43e983fdeb9af80447caa501337Romain Guy        }
581e91a9c7ab075c43e983fdeb9af80447caa501337Romain Guy
582484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy        private void printConfig(EGLConfig config) {
583484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy            int[] value = new int[1];
584484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy
585484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy            Log.d(LOG_TAG, "EGL configuration " + config + ":");
586484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy
587484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy            sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_RED_SIZE, value);
588484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy            Log.d(LOG_TAG, "  RED_SIZE = " + value[0]);
589484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy
590484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy            sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_GREEN_SIZE, value);
591484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy            Log.d(LOG_TAG, "  GREEN_SIZE = " + value[0]);
592484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy
593484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy            sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_BLUE_SIZE, value);
594484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy            Log.d(LOG_TAG, "  BLUE_SIZE = " + value[0]);
595484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy
596484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy            sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_ALPHA_SIZE, value);
597484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy            Log.d(LOG_TAG, "  ALPHA_SIZE = " + value[0]);
598484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy
599484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy            sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_DEPTH_SIZE, value);
600484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy            Log.d(LOG_TAG, "  DEPTH_SIZE = " + value[0]);
601484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy
602484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy            sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_STENCIL_SIZE, value);
603484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy            Log.d(LOG_TAG, "  STENCIL_SIZE = " + value[0]);
604484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy
605484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy            sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_SURFACE_TYPE, value);
60629d23ecfd8612ecd4a7b2140acd344934b73a558Romain Guy            Log.d(LOG_TAG, "  SURFACE_TYPE = 0x" + Integer.toHexString(value[0]));
607484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy        }
608484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy
609648251710162cdaf7371012a1cbb79b9bc5bc0e4Dianne Hackborn        GL createEglSurface(SurfaceHolder holder) throws Surface.OutOfResourcesException {
610e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            // Check preconditions.
611fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy            if (sEgl == null) {
612e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                throw new RuntimeException("egl not initialized");
613e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            }
614fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy            if (sEglDisplay == null) {
615e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                throw new RuntimeException("eglDisplay not initialized");
616e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            }
617fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy            if (sEglConfig == null) {
618069ea0e31a0aa283c83fae79f31a1798a6d85ddeRomain Guy                throw new RuntimeException("eglConfig not initialized");
619e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            }
620566b3efb25299d2a9c8ae827522802bad965426aRomain Guy            if (Thread.currentThread() != mEglThread) {
621fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy                throw new IllegalStateException("HardwareRenderer cannot be used "
622fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy                        + "from multiple threads");
623fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy            }
624e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
6252d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy            /*
626e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy             *  The window size has changed, so we need to create a new
627e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy             *  surface.
6282d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy             */
629484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy            if (mEglSurface != null && mEglSurface != EGL_NO_SURFACE) {
630e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                /*
631e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                 * Unbind and destroy the old EGL surface, if
632e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                 * there is one.
633e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                 */
634484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
635fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy                sEgl.eglDestroySurface(sEglDisplay, mEglSurface);
636e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            }
637e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
638e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            // Create an EGL surface we can render into.
639fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy            mEglSurface = sEgl.eglCreateWindowSurface(sEglDisplay, sEglConfig, holder, null);
640e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
641484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy            if (mEglSurface == null || mEglSurface == EGL_NO_SURFACE) {
642fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy                int error = sEgl.eglGetError();
643484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                if (error == EGL_BAD_NATIVE_WINDOW) {
6447d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                    Log.e(LOG_TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
645e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                    return null;
646e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                }
6475d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                throw new RuntimeException("createWindowSurface failed "
6485d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                        + getEGLErrorString(error));
649e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            }
650e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
6512d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy            /*
6522d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy             * Before we can issue GL commands, we need to make sure
6532d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy             * the context is current and bound to a surface.
6542d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy             */
655566b3efb25299d2a9c8ae827522802bad965426aRomain Guy            if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
656648251710162cdaf7371012a1cbb79b9bc5bc0e4Dianne Hackborn                throw new Surface.OutOfResourcesException("eglMakeCurrent failed "
6575d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                        + getEGLErrorString(sEgl.eglGetError()));
658e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            }
6596f7d9394ec69e9fb38ca5fc2caf6d2aef6f7442dRomain Guy
6606f7d9394ec69e9fb38ca5fc2caf6d2aef6f7442dRomain Guy            // If mDirtyRegions is set, this means we have an EGL configuration
6616f7d9394ec69e9fb38ca5fc2caf6d2aef6f7442dRomain Guy            // with EGL_SWAP_BEHAVIOR_PRESERVED_BIT set
6627e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy            if (sDirtyRegions) {
6637e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy                if (!(mDirtyRegionsEnabled = GLES20Canvas.preserveBackBuffer())) {
6647d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                    Log.w(LOG_TAG, "Backbuffer cannot be preserved");
6657d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                }
6667e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy            } else if (sDirtyRegionsRequested) {
6676f7d9394ec69e9fb38ca5fc2caf6d2aef6f7442dRomain Guy                // If mDirtyRegions is not set, our EGL configuration does not
6686f7d9394ec69e9fb38ca5fc2caf6d2aef6f7442dRomain Guy                // have EGL_SWAP_BEHAVIOR_PRESERVED_BIT; however, the default
6696f7d9394ec69e9fb38ca5fc2caf6d2aef6f7442dRomain Guy                // swap behavior might be EGL_BUFFER_PRESERVED, which means we
6706f7d9394ec69e9fb38ca5fc2caf6d2aef6f7442dRomain Guy                // want to set mDirtyRegions. We try to do this only if dirty
6716f7d9394ec69e9fb38ca5fc2caf6d2aef6f7442dRomain Guy                // regions were initially requested as part of the device
6726f7d9394ec69e9fb38ca5fc2caf6d2aef6f7442dRomain Guy                // configuration (see RENDER_DIRTY_REGIONS)
6737e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy                mDirtyRegionsEnabled = GLES20Canvas.isBackBufferPreserved();
6747d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy            }
675e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
676566b3efb25299d2a9c8ae827522802bad965426aRomain Guy            return mEglContext.getGL();
6772d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        }
6782d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
679e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
680912a7b32d0c59ba38265c5dd6ff84ce93f909a7fRomain Guy            int[] attribs = { EGL_CONTEXT_CLIENT_VERSION, mGlVersion, EGL_NONE };
681e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
682484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy            return egl.eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT,
683912a7b32d0c59ba38265c5dd6ff84ce93f909a7fRomain Guy                    mGlVersion != 0 ? attribs : null);
684e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        }
685e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
686e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        @Override
6874caa4ed120a86e855d4d3b6b455c6fb9ca22e365Romain Guy        void destroy(boolean full) {
6884caa4ed120a86e855d4d3b6b455c6fb9ca22e365Romain Guy            if (full && mCanvas != null) {
6894caa4ed120a86e855d4d3b6b455c6fb9ca22e365Romain Guy                mCanvas = null;
6904caa4ed120a86e855d4d3b6b455c6fb9ca22e365Romain Guy            }
6914caa4ed120a86e855d4d3b6b455c6fb9ca22e365Romain Guy
692fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy            if (!isEnabled() || mDestroyed) return;
693fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy
694fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy            mDestroyed = true;
695e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
696484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy            sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
697fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy            sEgl.eglDestroySurface(sEglDisplay, mEglSurface);
6982d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
6992d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy            mEglSurface = null;
700e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            mGl = null;
701fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy
7022d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy            setEnabled(false);
703fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        }
704fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy
7052d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        @Override
706039857520b1a03a52051b966d87d587225bdfcc3Romain Guy        void invalidate() {
7077e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy            // Cancels any existing buffer to ensure we'll get a buffer
7087e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy            // of the right size before we call eglSwapBuffers
709484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy            sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE,
710484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                    EGL_NO_SURFACE, EGL_NO_CONTEXT);
711039857520b1a03a52051b966d87d587225bdfcc3Romain Guy        }
712039857520b1a03a52051b966d87d587225bdfcc3Romain Guy
713039857520b1a03a52051b966d87d587225bdfcc3Romain Guy        @Override
714039857520b1a03a52051b966d87d587225bdfcc3Romain Guy        boolean validate() {
715039857520b1a03a52051b966d87d587225bdfcc3Romain Guy            return checkCurrent() != SURFACE_STATE_ERROR;
7167e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy        }
7177e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy
7187e1160e8664a9c5c79367f4ba3c2266a39bbcef5Romain Guy        @Override
719fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        void setup(int width, int height) {
720912a7b32d0c59ba38265c5dd6ff84ce93f909a7fRomain Guy            checkCurrent();
721fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy            mCanvas.setViewport(width, height);
722e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        }
7237d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy
724e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        boolean canDraw() {
725e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            return mGl != null && mCanvas != null;
726e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        }
727e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
7287d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy        void onPreDraw(Rect dirty) {
729e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        }
730e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
731b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy        void onPostDraw() {
732b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy        }
7332d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
7342d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        @Override
7357d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy        void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks,
7367d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                Rect dirty) {
737e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            if (canDraw()) {
73802ccac69fd1c0a03c24c5f3ace0ad4bed337b1fdRomain Guy                if (!hasDirtyRegions()) {
7397d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                    dirty = null;
7407d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                }
7412d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy                attachInfo.mIgnoreDirtyState = true;
74202ccac69fd1c0a03c24c5f3ace0ad4bed337b1fdRomain Guy                attachInfo.mDrawingTime = SystemClock.uptimeMillis();
74302ccac69fd1c0a03c24c5f3ace0ad4bed337b1fdRomain Guy
7442d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy                view.mPrivateFlags |= View.DRAWN;
745039857520b1a03a52051b966d87d587225bdfcc3Romain Guy
746d88f54c5c4ce59585b8b9e6009836f14c00be743Romain Guy                final int surfaceState = checkCurrent();
747d88f54c5c4ce59585b8b9e6009836f14c00be743Romain Guy                if (surfaceState != SURFACE_STATE_ERROR) {
748d88f54c5c4ce59585b8b9e6009836f14c00be743Romain Guy                    // We had to change the current surface and/or context, redraw everything
749d88f54c5c4ce59585b8b9e6009836f14c00be743Romain Guy                    if (surfaceState == SURFACE_STATE_UPDATED) {
750d88f54c5c4ce59585b8b9e6009836f14c00be743Romain Guy                        dirty = null;
751d88f54c5c4ce59585b8b9e6009836f14c00be743Romain Guy                    }
752d88f54c5c4ce59585b8b9e6009836f14c00be743Romain Guy
7537d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                    onPreDraw(dirty);
75462687ec12cb8e0b1d4044a235b1387b9a8c3b4b4Romain Guy
755daf98e941e140e8739458126640183b9f296a2abChet Haase                    HardwareCanvas canvas = mCanvas;
756daf98e941e140e8739458126640183b9f296a2abChet Haase                    attachInfo.mHardwareCanvas = canvas;
7577d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy
758b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy                    int saveCount = canvas.save();
759b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy                    callbacks.onHardwarePreDraw(canvas);
760daf98e941e140e8739458126640183b9f296a2abChet Haase
761b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy                    try {
762daf98e941e140e8739458126640183b9f296a2abChet Haase                        view.mRecreateDisplayList =
763daf98e941e140e8739458126640183b9f296a2abChet Haase                                (view.mPrivateFlags & View.INVALIDATED) == View.INVALIDATED;
764daf98e941e140e8739458126640183b9f296a2abChet Haase                        view.mPrivateFlags &= ~View.INVALIDATED;
7657d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy
766daf98e941e140e8739458126640183b9f296a2abChet Haase                        DisplayList displayList = view.getDisplayList();
767daf98e941e140e8739458126640183b9f296a2abChet Haase                        if (displayList != null) {
7687b5b6abf852c039983eded25ebe43a70fef5a4abRomain Guy                            if (canvas.drawDisplayList(displayList, view.getWidth(),
7697b5b6abf852c039983eded25ebe43a70fef5a4abRomain Guy                                    view.getHeight(), mRedrawClip)) {
770e294d41593f13edc5598cf62f8a89e573b3eb653Romain Guy                                if (mRedrawClip.isEmpty() || view.getParent() == null) {
771cabfcc1364eb7e4de0b15b3574fba45027b45cfcRomain Guy                                    view.invalidate();
772cabfcc1364eb7e4de0b15b3574fba45027b45cfcRomain Guy                                } else {
773cabfcc1364eb7e4de0b15b3574fba45027b45cfcRomain Guy                                    view.getParent().invalidateChild(view, mRedrawClip);
774cabfcc1364eb7e4de0b15b3574fba45027b45cfcRomain Guy                                }
775cabfcc1364eb7e4de0b15b3574fba45027b45cfcRomain Guy                                mRedrawClip.setEmpty();
776daf98e941e140e8739458126640183b9f296a2abChet Haase                            }
777daf98e941e140e8739458126640183b9f296a2abChet Haase                        } else {
778daf98e941e140e8739458126640183b9f296a2abChet Haase                            // Shouldn't reach here
779daf98e941e140e8739458126640183b9f296a2abChet Haase                            view.draw(canvas);
780daf98e941e140e8739458126640183b9f296a2abChet Haase                        }
7817d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy
7827d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                        if (DEBUG_DIRTY_REGION) {
7837d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                            if (mDebugPaint == null) {
7847d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                                mDebugPaint = new Paint();
7857d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                                mDebugPaint.setColor(0x7fff0000);
7867d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                            }
7877d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                            if (dirty != null && (mFrameCount++ & 1) == 0) {
7887d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                                canvas.drawRect(dirty, mDebugPaint);
7897d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                            }
7907d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                        }
791b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy                    } finally {
792b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy                        callbacks.onHardwarePostDraw(canvas);
793b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy                        canvas.restoreToCount(saveCount);
794daf98e941e140e8739458126640183b9f296a2abChet Haase                        view.mRecreateDisplayList = false;
795b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy                    }
796daf98e941e140e8739458126640183b9f296a2abChet Haase
797b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy                    onPostDraw();
798daf98e941e140e8739458126640183b9f296a2abChet Haase
799b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy                    attachInfo.mIgnoreDirtyState = false;
8004e91a180be46c0c7c3bf398d4df4cbe2404216b5Jeff Brown
801b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy                    sEgl.eglSwapBuffers(sEglDisplay, mEglSurface);
802b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy                    checkEglErrors();
8039a40babc62416259d18783ce8c03c00042ec317bRomain Guy                }
8042d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy            }
8052d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        }
806039857520b1a03a52051b966d87d587225bdfcc3Romain Guy
807039857520b1a03a52051b966d87d587225bdfcc3Romain Guy        /**
808566b3efb25299d2a9c8ae827522802bad965426aRomain Guy         * Ensures the current EGL context is the one we expect.
809039857520b1a03a52051b966d87d587225bdfcc3Romain Guy         *
810039857520b1a03a52051b966d87d587225bdfcc3Romain Guy         * @return {@link #SURFACE_STATE_ERROR} if the correct EGL context cannot be made current,
811039857520b1a03a52051b966d87d587225bdfcc3Romain Guy         *         {@link #SURFACE_STATE_UPDATED} if the EGL context was changed or
812039857520b1a03a52051b966d87d587225bdfcc3Romain Guy         *         {@link #SURFACE_STATE_SUCCESS} if the EGL context was the correct one
813039857520b1a03a52051b966d87d587225bdfcc3Romain Guy         */
814912a7b32d0c59ba38265c5dd6ff84ce93f909a7fRomain Guy        int checkCurrent() {
815566b3efb25299d2a9c8ae827522802bad965426aRomain Guy            if (mEglThread != Thread.currentThread()) {
816039857520b1a03a52051b966d87d587225bdfcc3Romain Guy                throw new IllegalStateException("Hardware acceleration can only be used with a " +
817566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                        "single UI thread.\nOriginal thread: " + mEglThread + "\n" +
818039857520b1a03a52051b966d87d587225bdfcc3Romain Guy                        "Current thread: " + Thread.currentThread());
819039857520b1a03a52051b966d87d587225bdfcc3Romain Guy            }
820039857520b1a03a52051b966d87d587225bdfcc3Romain Guy
821566b3efb25299d2a9c8ae827522802bad965426aRomain Guy            if (!mEglContext.equals(sEgl.eglGetCurrentContext()) ||
822484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                    !mEglSurface.equals(sEgl.eglGetCurrentSurface(EGL_DRAW))) {
823566b3efb25299d2a9c8ae827522802bad965426aRomain Guy                if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
8249745fae73b584f3e9a9c304098ed9b11f506e93bRomain Guy                    fallback(true);
8259745fae73b584f3e9a9c304098ed9b11f506e93bRomain Guy                    Log.e(LOG_TAG, "eglMakeCurrent failed " +
8269745fae73b584f3e9a9c304098ed9b11f506e93bRomain Guy                            getEGLErrorString(sEgl.eglGetError()));
827d88f54c5c4ce59585b8b9e6009836f14c00be743Romain Guy                    return SURFACE_STATE_ERROR;
828d88f54c5c4ce59585b8b9e6009836f14c00be743Romain Guy                } else {
829d88f54c5c4ce59585b8b9e6009836f14c00be743Romain Guy                    return SURFACE_STATE_UPDATED;
830fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy                }
831fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy            }
832d88f54c5c4ce59585b8b9e6009836f14c00be743Romain Guy            return SURFACE_STATE_SUCCESS;
833fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        }
834e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy    }
835fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy
836e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy    /**
837e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy     * Hardware renderer using OpenGL ES 2.0.
838e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy     */
839e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy    static class Gl20Renderer extends GlRenderer {
840e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        private GLES20Canvas mGlCanvas;
841e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
842912a7b32d0c59ba38265c5dd6ff84ce93f909a7fRomain Guy        private static EGLSurface sPbuffer;
843912a7b32d0c59ba38265c5dd6ff84ce93f909a7fRomain Guy        private static final Object[] sPbufferLock = new Object[0];
844912a7b32d0c59ba38265c5dd6ff84ce93f909a7fRomain Guy
845e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        Gl20Renderer(boolean translucent) {
846e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            super(2, translucent);
847e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        }
848e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
8492d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        @Override
850fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        GLES20Canvas createCanvas() {
8516b7bd24659fb175fe1f0e97c86c18969918b496aRomain Guy            return mGlCanvas = new GLES20Canvas(mTranslucent);
852e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        }
853e91a9c7ab075c43e983fdeb9af80447caa501337Romain Guy
854e91a9c7ab075c43e983fdeb9af80447caa501337Romain Guy        @Override
855e91a9c7ab075c43e983fdeb9af80447caa501337Romain Guy        int[] getConfig(boolean dirtyRegions) {
856e91a9c7ab075c43e983fdeb9af80447caa501337Romain Guy            return new int[] {
857484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                    EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
858484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                    EGL_RED_SIZE, 8,
859484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                    EGL_GREEN_SIZE, 8,
860484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                    EGL_BLUE_SIZE, 8,
861484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                    EGL_ALPHA_SIZE, 8,
862484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                    EGL_DEPTH_SIZE, 0,
863484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                    EGL_STENCIL_SIZE, 0,
864484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                    EGL_SURFACE_TYPE, EGL_WINDOW_BIT |
86508645eb0f4a8d73b2b2f26d3232f45cf459a27bcRomain Guy                            (dirtyRegions ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0),
866484c719c1c4a86d10d7be821782a808d0e12ea4eRomain Guy                    EGL_NONE
867e91a9c7ab075c43e983fdeb9af80447caa501337Romain Guy            };
868e91a9c7ab075c43e983fdeb9af80447caa501337Romain Guy        }
869e91a9c7ab075c43e983fdeb9af80447caa501337Romain Guy
870b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy        @Override
871b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy        boolean canDraw() {
872b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy            return super.canDraw() && mGlCanvas != null;
873b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy        }
874e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
875e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        @Override
8767d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy        void onPreDraw(Rect dirty) {
8777d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy            mGlCanvas.onPreDraw(dirty);
878e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        }
879e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
880b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy        @Override
881b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy        void onPostDraw() {
882b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy            mGlCanvas.onPostDraw();
883b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy        }
884b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy
885b051e895ccb696604349c6c5efe7c4747e1d1ab6Romain Guy        @Override
88667f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy        void destroy(boolean full) {
887b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy            try {
888b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy                super.destroy(full);
889b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy            } finally {
890b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy                if (full && mGlCanvas != null) {
891b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy                    mGlCanvas = null;
892b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy                }
89367f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy            }
89467f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy        }
89567f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy
89667f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy        @Override
8979ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy        void setup(int width, int height) {
8989ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy            super.setup(width, height);
8999ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy            if (mVsyncDisabled) {
9009ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy                GLES20Canvas.disableVsync();
9019ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy            }
9029ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy        }
9039ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy
9049ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy        @Override
905162a0217563f4665da6eb183dfce0fef740f641fJeff Brown        DisplayList createDisplayList() {
906162a0217563f4665da6eb183dfce0fef740f641fJeff Brown            return new GLES20DisplayList();
907b051e895ccb696604349c6c5efe7c4747e1d1ab6Romain Guy        }
908aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy
909aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy        @Override
910a9489274d67b540804aafb587a226f7c2ae4464dRomain Guy        HardwareLayer createHardwareLayer(boolean isOpaque) {
911a9489274d67b540804aafb587a226f7c2ae4464dRomain Guy            return new GLES20TextureLayer(isOpaque);
912aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy        }
913aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy
9146c319ca1275c8db892c39b48fc54864c949f9171Romain Guy        @Override
9156c319ca1275c8db892c39b48fc54864c949f9171Romain Guy        HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque) {
916aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy            return new GLES20RenderLayer(width, height, isOpaque);
917aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy        }
918aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy
919aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy        @Override
920e5e0c50f7dfaccc220725c5595080e921ffda1e4Romain Guy        SurfaceTexture createSurfaceTexture(HardwareLayer layer) {
921aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy            return ((GLES20TextureLayer) layer).getSurfaceTexture();
922aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy        }
923aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy
924912a7b32d0c59ba38265c5dd6ff84ce93f909a7fRomain Guy        static void trimMemory(int level) {
925912a7b32d0c59ba38265c5dd6ff84ce93f909a7fRomain Guy            if (sEgl == null || sEglConfig == null) return;
926912a7b32d0c59ba38265c5dd6ff84ce93f909a7fRomain Guy
927912a7b32d0c59ba38265c5dd6ff84ce93f909a7fRomain Guy            EGLContext eglContext = sEglContextStorage.get();
928912a7b32d0c59ba38265c5dd6ff84ce93f909a7fRomain Guy            // We do not have OpenGL objects
929912a7b32d0c59ba38265c5dd6ff84ce93f909a7fRomain Guy            if (eglContext == null) {
930912a7b32d0c59ba38265c5dd6ff84ce93f909a7fRomain Guy                return;
931912a7b32d0c59ba38265c5dd6ff84ce93f909a7fRomain Guy            } else {
932912a7b32d0c59ba38265c5dd6ff84ce93f909a7fRomain Guy                synchronized (sPbufferLock) {
933912a7b32d0c59ba38265c5dd6ff84ce93f909a7fRomain Guy                    // Create a temporary 1x1 pbuffer so we have a context
934912a7b32d0c59ba38265c5dd6ff84ce93f909a7fRomain Guy                    // to clear our OpenGL objects
935912a7b32d0c59ba38265c5dd6ff84ce93f909a7fRomain Guy                    if (sPbuffer == null) {
936912a7b32d0c59ba38265c5dd6ff84ce93f909a7fRomain Guy                        sPbuffer = sEgl.eglCreatePbufferSurface(sEglDisplay, sEglConfig, new int[] {
937912a7b32d0c59ba38265c5dd6ff84ce93f909a7fRomain Guy                                EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE
938912a7b32d0c59ba38265c5dd6ff84ce93f909a7fRomain Guy                        });
939912a7b32d0c59ba38265c5dd6ff84ce93f909a7fRomain Guy                    }
940912a7b32d0c59ba38265c5dd6ff84ce93f909a7fRomain Guy                }
941912a7b32d0c59ba38265c5dd6ff84ce93f909a7fRomain Guy                sEgl.eglMakeCurrent(sEglDisplay, sPbuffer, sPbuffer, eglContext);
9422d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy            }
943912a7b32d0c59ba38265c5dd6ff84ce93f909a7fRomain Guy
944bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy            switch (level) {
945bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy                case ComponentCallbacks.TRIM_MEMORY_MODERATE:
946bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy                    GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_MODERATE);
947bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy                    break;
948bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy                case ComponentCallbacks.TRIM_MEMORY_COMPLETE:
949bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy                    GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_FULL);
950bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy                    break;
951bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy            }
952bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy        }
953912a7b32d0c59ba38265c5dd6ff84ce93f909a7fRomain Guy
954912a7b32d0c59ba38265c5dd6ff84ce93f909a7fRomain Guy        static HardwareRenderer create(boolean translucent) {
955912a7b32d0c59ba38265c5dd6ff84ce93f909a7fRomain Guy            if (GLES20Canvas.isAvailable()) {
956912a7b32d0c59ba38265c5dd6ff84ce93f909a7fRomain Guy                return new Gl20Renderer(translucent);
957912a7b32d0c59ba38265c5dd6ff84ce93f909a7fRomain Guy            }
958912a7b32d0c59ba38265c5dd6ff84ce93f909a7fRomain Guy            return null;
959912a7b32d0c59ba38265c5dd6ff84ce93f909a7fRomain Guy        }
9602d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    }
9612d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy}
962