HardwareRenderer.java revision 62687ec12cb8e0b1d4044a235b1387b9a8c3b4b4
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
202d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guyimport android.graphics.Canvas;
217d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guyimport android.graphics.Paint;
227d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guyimport android.graphics.Rect;
232d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guyimport android.os.SystemClock;
249a40babc62416259d18783ce8c03c00042ec317bRomain Guyimport android.util.EventLog;
25e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guyimport android.util.Log;
262d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
272d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guyimport javax.microedition.khronos.egl.EGL10;
282d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guyimport javax.microedition.khronos.egl.EGL11;
292d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guyimport javax.microedition.khronos.egl.EGLConfig;
302d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guyimport javax.microedition.khronos.egl.EGLContext;
312d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guyimport javax.microedition.khronos.egl.EGLDisplay;
322d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guyimport javax.microedition.khronos.egl.EGLSurface;
33e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guyimport javax.microedition.khronos.opengles.GL;
342d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
352d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy/**
362d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy * Interface for rendering a ViewRoot using hardware acceleration.
372d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy *
382d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy * @hide
392d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy */
4061c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guypublic abstract class HardwareRenderer {
414f6aff386045000c2c03b903c7109cb42092b7eaRomain Guy    static final String LOG_TAG = "HardwareRenderer";
42fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy
435233920a216302b4aa03b100c32e8b3efe33cbc6Romain Guy    /**
447d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy     * Turn on to only refresh the parts of the screen that need updating.
457d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy     */
467d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    public static final boolean RENDER_DIRTY_REGIONS = true;
477d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy
487d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    /**
497d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy     * Turn on to draw dirty regions every other frame.
507d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy     */
517d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    private static final boolean DEBUG_DIRTY_REGION = false;
527d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy
537d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    /**
545233920a216302b4aa03b100c32e8b3efe33cbc6Romain Guy     * A process can set this flag to false to prevent the use of hardware
555233920a216302b4aa03b100c32e8b3efe33cbc6Romain Guy     * rendering.
565233920a216302b4aa03b100c32e8b3efe33cbc6Romain Guy     *
575233920a216302b4aa03b100c32e8b3efe33cbc6Romain Guy     * @hide
585233920a216302b4aa03b100c32e8b3efe33cbc6Romain Guy     */
595233920a216302b4aa03b100c32e8b3efe33cbc6Romain Guy    public static boolean sRendererDisabled = false;
605233920a216302b4aa03b100c32e8b3efe33cbc6Romain Guy
612d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    private boolean mEnabled;
622d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    private boolean mRequested = true;
632d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
642d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    /**
6567f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy     * Invoke this method to disable hardware rendering in the current process.
665233920a216302b4aa03b100c32e8b3efe33cbc6Romain Guy     *
675233920a216302b4aa03b100c32e8b3efe33cbc6Romain Guy     * @hide
685233920a216302b4aa03b100c32e8b3efe33cbc6Romain Guy     */
695233920a216302b4aa03b100c32e8b3efe33cbc6Romain Guy    public static void disable() {
705233920a216302b4aa03b100c32e8b3efe33cbc6Romain Guy        sRendererDisabled = true;
715233920a216302b4aa03b100c32e8b3efe33cbc6Romain Guy    }
725233920a216302b4aa03b100c32e8b3efe33cbc6Romain Guy
735233920a216302b4aa03b100c32e8b3efe33cbc6Romain Guy    /**
7461c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy     * Indicates whether hardware acceleration is available under any form for
7561c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy     * the view hierarchy.
7661c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy     *
7761c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy     * @return True if the view hierarchy can potentially be hardware accelerated,
7861c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy     *         false otherwise
7961c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy     */
8061c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy    public static boolean isAvailable() {
8161c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        return GLES20Canvas.isAvailable();
8261c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy    }
8361c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy
8461c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy    /**
852d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * Destroys the hardware rendering context.
864caa4ed120a86e855d4d3b6b455c6fb9ca22e365Romain Guy     *
874caa4ed120a86e855d4d3b6b455c6fb9ca22e365Romain Guy     * @param full If true, destroys all associated resources.
882d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     */
894caa4ed120a86e855d4d3b6b455c6fb9ca22e365Romain Guy    abstract void destroy(boolean full);
902d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
912d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    /**
922d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * Initializes the hardware renderer for the specified surface.
932d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     *
942d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * @param holder The holder for the surface to hardware accelerate.
952d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     *
962d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * @return True if the initialization was successful, false otherwise.
972d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     */
982d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    abstract boolean initialize(SurfaceHolder holder);
992a83f001fdb189f945e82e81e717ba204824b112Romain Guy
1002a83f001fdb189f945e82e81e717ba204824b112Romain Guy    /**
1012a83f001fdb189f945e82e81e717ba204824b112Romain Guy     * Updates the hardware renderer for the specified surface.
1022a83f001fdb189f945e82e81e717ba204824b112Romain Guy     *
1032a83f001fdb189f945e82e81e717ba204824b112Romain Guy     * @param holder The holder for the surface to hardware accelerate.
1042a83f001fdb189f945e82e81e717ba204824b112Romain Guy     */
1052a83f001fdb189f945e82e81e717ba204824b112Romain Guy    abstract void updateSurface(SurfaceHolder holder);
1062d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
1072d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    /**
1082d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * Setup the hardware renderer for drawing. This is called for every
1092d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * frame to draw.
1102d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     *
1112d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * @param width Width of the drawing surface.
1122d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * @param height Height of the drawing surface.
1132d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     */
114fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    abstract void setup(int width, int height);
1152d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
1160f761d6b8f5d5a607c87dbcdca6fe0ec7911970eDianne Hackborn    interface HardwareDrawCallbacks {
1170f761d6b8f5d5a607c87dbcdca6fe0ec7911970eDianne Hackborn        void onHardwarePreDraw(Canvas canvas);
1180f761d6b8f5d5a607c87dbcdca6fe0ec7911970eDianne Hackborn        void onHardwarePostDraw(Canvas canvas);
1190f761d6b8f5d5a607c87dbcdca6fe0ec7911970eDianne Hackborn    }
1200f761d6b8f5d5a607c87dbcdca6fe0ec7911970eDianne Hackborn
1212d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    /**
1222d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * Draws the specified view.
1237d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy     *
1242d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * @param view The view to draw.
1252d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * @param attachInfo AttachInfo tied to the specified view.
1267d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy     * @param callbacks Callbacks invoked when drawing happens.
1277d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy     * @param dirty The dirty rectangle to update, can be null.
1282d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     */
1297d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    abstract void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks,
1307d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy            Rect dirty);
1312d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
1322d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    /**
13353ca03d9a3a6a95286302802173c4820b16328ceRomain Guy     * Creates a new display list that can be used to record batches of
13453ca03d9a3a6a95286302802173c4820b16328ceRomain Guy     * drawing operations.
135b051e895ccb696604349c6c5efe7c4747e1d1ab6Romain Guy     *
13653ca03d9a3a6a95286302802173c4820b16328ceRomain Guy     * @return A new display list.
137b051e895ccb696604349c6c5efe7c4747e1d1ab6Romain Guy     */
138daf98e941e140e8739458126640183b9f296a2abChet Haase    abstract DisplayList createDisplayList(View v);
139b051e895ccb696604349c6c5efe7c4747e1d1ab6Romain Guy
140b051e895ccb696604349c6c5efe7c4747e1d1ab6Romain Guy    /**
1416c319ca1275c8db892c39b48fc54864c949f9171Romain Guy     * Creates a new hardware layer.
1426c319ca1275c8db892c39b48fc54864c949f9171Romain Guy     *
1436c319ca1275c8db892c39b48fc54864c949f9171Romain Guy     * @param width The minimum width of the layer
1446c319ca1275c8db892c39b48fc54864c949f9171Romain Guy     * @param height The minimum height of the layer
1456c319ca1275c8db892c39b48fc54864c949f9171Romain Guy     * @param isOpaque Whether the layer should be opaque or not
1466c319ca1275c8db892c39b48fc54864c949f9171Romain Guy     *
1476c319ca1275c8db892c39b48fc54864c949f9171Romain Guy     * @return A hardware layer
1486c319ca1275c8db892c39b48fc54864c949f9171Romain Guy     */
1496c319ca1275c8db892c39b48fc54864c949f9171Romain Guy    abstract HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque);
1506c319ca1275c8db892c39b48fc54864c949f9171Romain Guy
1516c319ca1275c8db892c39b48fc54864c949f9171Romain Guy    /**
1522d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * Initializes the hardware renderer for the specified surface and setup the
1532d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * renderer for drawing, if needed. This is invoked when the ViewRoot has
1542d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * potentially lost the hardware renderer. The hardware renderer should be
1552d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * reinitialized and setup when the render {@link #isRequested()} and
1562d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * {@link #isEnabled()}.
1572d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     *
1582d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * @param width The width of the drawing surface.
1592d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * @param height The height of the drawing surface.
1602d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * @param attachInfo The
1612d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * @param holder
1622d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     */
1632d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    void initializeIfNeeded(int width, int height, View.AttachInfo attachInfo,
1642d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy            SurfaceHolder holder) {
1652d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        if (isRequested()) {
1662d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy            // We lost the gl context, so recreate it.
1672d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy            if (!isEnabled()) {
1682d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy                if (initialize(holder)) {
169fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy                    setup(width, height);
1702d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy                }
1712d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy            }
1722d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        }
1732d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    }
1742d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
1752d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    /**
1762d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * Creates a hardware renderer using OpenGL.
1772d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     *
1782d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * @param glVersion The version of OpenGL to use (1 for OpenGL 1, 11 for OpenGL 1.1, etc.)
179e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy     * @param translucent True if the surface is translucent, false otherwise
1802d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     *
1812d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * @return A hardware renderer backed by OpenGL.
1822d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     */
183e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    static HardwareRenderer createGlRenderer(int glVersion, boolean translucent) {
1842d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        switch (glVersion) {
185e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            case 2:
186163935113919a184122b8b3bd672ef08c8df65dcRomain Guy                return Gl20Renderer.create(translucent);
1872d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        }
1882d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        throw new IllegalArgumentException("Unknown GL version: " + glVersion);
1892d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    }
1902d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
1912d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    /**
1922d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * Indicates whether hardware acceleration is currently enabled.
1932d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     *
1942d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * @return True if hardware acceleration is in use, false otherwise.
1952d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     */
1962d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    boolean isEnabled() {
1972d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        return mEnabled;
1982d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    }
1992d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
2002d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    /**
2012d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * Indicates whether hardware acceleration is currently enabled.
2022d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     *
2032d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * @param enabled True if the hardware renderer is in use, false otherwise.
2042d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     */
2052d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    void setEnabled(boolean enabled) {
2062d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        mEnabled = enabled;
2072d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    }
2082d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
2092d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    /**
2102d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * Indicates whether hardware acceleration is currently request but not
2112d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * necessarily enabled yet.
2122d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     *
2132d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * @return True if requested, false otherwise.
2142d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     */
2152d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    boolean isRequested() {
2162d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        return mRequested;
2172d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    }
2182d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
2192d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    /**
2209745fae73b584f3e9a9c304098ed9b11f506e93bRomain Guy     * Indicates whether hardware acceleration is currently requested but not
2212d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * necessarily enabled yet.
2222d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     *
2232d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     * @return True to request hardware acceleration, false otherwise.
2242d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy     */
2252d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    void setRequested(boolean requested) {
2262d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        mRequested = requested;
2272d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    }
2282d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
2292d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    @SuppressWarnings({"deprecation"})
230e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy    static abstract class GlRenderer extends HardwareRenderer {
231e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        private static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
2327d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy        private static final int EGL_SURFACE_TYPE = 0x3033;
2337d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy        private static final int EGL_SWAP_BEHAVIOR_PRESERVED_BIT = 0x0400;
234e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
235d88f54c5c4ce59585b8b9e6009836f14c00be743Romain Guy        private static final int SURFACE_STATE_ERROR = 0;
236d88f54c5c4ce59585b8b9e6009836f14c00be743Romain Guy        private static final int SURFACE_STATE_SUCCESS = 1;
237d88f54c5c4ce59585b8b9e6009836f14c00be743Romain Guy        private static final int SURFACE_STATE_UPDATED = 2;
238d88f54c5c4ce59585b8b9e6009836f14c00be743Romain Guy
239fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        static EGLContext sEglContext;
240fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        static EGL10 sEgl;
241fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        static EGLDisplay sEglDisplay;
242fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        static EGLConfig sEglConfig;
243e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
244fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        private static Thread sEglThread;
245fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy
246fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        EGLSurface mEglSurface;
247fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy
248e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        GL mGl;
24967f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy        HardwareCanvas mCanvas;
2507d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy        int mFrameCount;
2517d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy        Paint mDebugPaint;
2527d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy
2532d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
254e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        final int mGlVersion;
255e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        final boolean mTranslucent;
2562d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
257fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        private boolean mDestroyed;
258fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy
259e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        GlRenderer(int glVersion, boolean translucent) {
260e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            mGlVersion = glVersion;
261e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            mTranslucent = translucent;
2622d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        }
2632d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
264e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        /**
2655d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd         * Return a string for the EGL error code, or the hex representation
266d10cd5765a2b706fc174f16b951d6b0a5d3740d3Romain Guy         * if the error is unknown.
267d10cd5765a2b706fc174f16b951d6b0a5d3740d3Romain Guy         *
268d10cd5765a2b706fc174f16b951d6b0a5d3740d3Romain Guy         * @param error The EGL error to convert into a String.
269d10cd5765a2b706fc174f16b951d6b0a5d3740d3Romain Guy         *
270d10cd5765a2b706fc174f16b951d6b0a5d3740d3Romain Guy         * @return An error string correponding to the EGL error code.
2715d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd         */
2725d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd        static String getEGLErrorString(int error) {
2735d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd            switch (error) {
2745d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                case EGL10.EGL_SUCCESS:
2755d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                    return "EGL_SUCCESS";
2765d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                case EGL10.EGL_NOT_INITIALIZED:
2775d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                    return "EGL_NOT_INITIALIZED";
2785d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                case EGL10.EGL_BAD_ACCESS:
2795d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                    return "EGL_BAD_ACCESS";
2805d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                case EGL10.EGL_BAD_ALLOC:
2815d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                    return "EGL_BAD_ALLOC";
2825d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                case EGL10.EGL_BAD_ATTRIBUTE:
2835d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                    return "EGL_BAD_ATTRIBUTE";
2845d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                case EGL10.EGL_BAD_CONFIG:
2855d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                    return "EGL_BAD_CONFIG";
2865d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                case EGL10.EGL_BAD_CONTEXT:
2875d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                    return "EGL_BAD_CONTEXT";
2885d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                case EGL10.EGL_BAD_CURRENT_SURFACE:
2895d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                    return "EGL_BAD_CURRENT_SURFACE";
2905d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                case EGL10.EGL_BAD_DISPLAY:
2915d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                    return "EGL_BAD_DISPLAY";
2925d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                case EGL10.EGL_BAD_MATCH:
2935d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                    return "EGL_BAD_MATCH";
2945d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                case EGL10.EGL_BAD_NATIVE_PIXMAP:
2955d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                    return "EGL_BAD_NATIVE_PIXMAP";
2965d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                case EGL10.EGL_BAD_NATIVE_WINDOW:
2975d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                    return "EGL_BAD_NATIVE_WINDOW";
2985d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                case EGL10.EGL_BAD_PARAMETER:
2995d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                    return "EGL_BAD_PARAMETER";
3005d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                case EGL10.EGL_BAD_SURFACE:
3015d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                    return "EGL_BAD_SURFACE";
3025d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                case EGL11.EGL_CONTEXT_LOST:
3035d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                    return "EGL_CONTEXT_LOST";
3045d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                default:
3055d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                    return "0x" + Integer.toHexString(error);
3065d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd            }
3075d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd        }
3085d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd
3095d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd        /**
3104caa4ed120a86e855d4d3b6b455c6fb9ca22e365Romain Guy         * Checks for OpenGL errors. If an error has occured, {@link #destroy(boolean)}
311e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy         * is invoked and the requested flag is turned off. The error code is
312e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy         * also logged as a warning.
313e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy         */
314b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy        void checkEglErrors() {
315e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            if (isEnabled()) {
316fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy                int error = sEgl.eglGetError();
317e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                if (error != EGL10.EGL_SUCCESS) {
318e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                    // something bad has happened revert to
319e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                    // normal rendering.
3209745fae73b584f3e9a9c304098ed9b11f506e93bRomain Guy                    fallback(error != EGL11.EGL_CONTEXT_LOST);
3215d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                    Log.w(LOG_TAG, "EGL error: " + getEGLErrorString(error));
322e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                }
3232d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy            }
3242d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        }
32567f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy
3269745fae73b584f3e9a9c304098ed9b11f506e93bRomain Guy        private void fallback(boolean fallback) {
3279745fae73b584f3e9a9c304098ed9b11f506e93bRomain Guy            destroy(true);
3289745fae73b584f3e9a9c304098ed9b11f506e93bRomain Guy            if (fallback) {
3299745fae73b584f3e9a9c304098ed9b11f506e93bRomain Guy                // we'll try again if it was context lost
3309745fae73b584f3e9a9c304098ed9b11f506e93bRomain Guy                setRequested(false);
3319745fae73b584f3e9a9c304098ed9b11f506e93bRomain Guy                Log.w(LOG_TAG, "Mountain View, we've had a problem here. "
3329745fae73b584f3e9a9c304098ed9b11f506e93bRomain Guy                        + "Switching back to software rendering.");
3339745fae73b584f3e9a9c304098ed9b11f506e93bRomain Guy            }
3349745fae73b584f3e9a9c304098ed9b11f506e93bRomain Guy        }
3359745fae73b584f3e9a9c304098ed9b11f506e93bRomain Guy
336e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        @Override
337e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        boolean initialize(SurfaceHolder holder) {
338e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            if (isRequested() && !isEnabled()) {
339e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                initializeEgl();
340e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                mGl = createEglSurface(holder);
341fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy                mDestroyed = false;
3422d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
343e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                if (mGl != null) {
344fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy                    int err = sEgl.eglGetError();
345e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                    if (err != EGL10.EGL_SUCCESS) {
3464caa4ed120a86e855d4d3b6b455c6fb9ca22e365Romain Guy                        destroy(true);
347e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                        setRequested(false);
348e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                    } else {
3494caa4ed120a86e855d4d3b6b455c6fb9ca22e365Romain Guy                        if (mCanvas == null) {
3504caa4ed120a86e855d4d3b6b455c6fb9ca22e365Romain Guy                            mCanvas = createCanvas();
351fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy                        }
352e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                        if (mCanvas != null) {
353e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                            setEnabled(true);
354e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                        } else {
355e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                            Log.w(LOG_TAG, "Hardware accelerated Canvas could not be created");
356e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                        }
357e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                    }
358e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
359e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                    return mCanvas != null;
360e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                }
361e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            }
362e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            return false;
363e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        }
3642a83f001fdb189f945e82e81e717ba204824b112Romain Guy
3652a83f001fdb189f945e82e81e717ba204824b112Romain Guy        @Override
3662a83f001fdb189f945e82e81e717ba204824b112Romain Guy        void updateSurface(SurfaceHolder holder) {
3672a83f001fdb189f945e82e81e717ba204824b112Romain Guy            if (isRequested() && isEnabled()) {
3682a83f001fdb189f945e82e81e717ba204824b112Romain Guy                createEglSurface(holder);
3692a83f001fdb189f945e82e81e717ba204824b112Romain Guy            }
3702a83f001fdb189f945e82e81e717ba204824b112Romain Guy        }
371e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
372fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        abstract GLES20Canvas createCanvas();
3732d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
374e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        void initializeEgl() {
375fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy            if (sEglContext != null) return;
376fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy
377fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy            sEglThread = Thread.currentThread();
378fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy            sEgl = (EGL10) EGLContext.getEGL();
379e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
380e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            // Get to the default display.
381fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy            sEglDisplay = sEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
382e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
383fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy            if (sEglDisplay == EGL10.EGL_NO_DISPLAY) {
3845d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                throw new RuntimeException("eglGetDisplay failed "
3855d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                        + getEGLErrorString(sEgl.eglGetError()));
386e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            }
387e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
388e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            // We can now initialize EGL for that display
389e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            int[] version = new int[2];
390fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy            if (!sEgl.eglInitialize(sEglDisplay, version)) {
3915d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                throw new RuntimeException("eglInitialize failed "
3925d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                        + getEGLErrorString(sEgl.eglGetError()));
393e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            }
394fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy            sEglConfig = getConfigChooser(mGlVersion).chooseConfig(sEgl, sEglDisplay);
395e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
3962d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy            /*
397e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            * Create an EGL context. We want to do this as rarely as we can, because an
398e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            * EGL context is a somewhat heavy object.
399e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            */
400fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy            sEglContext = createContext(sEgl, sEglDisplay, sEglConfig);
401e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        }
402e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
403e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        GL createEglSurface(SurfaceHolder holder) {
404e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            // Check preconditions.
405fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy            if (sEgl == null) {
406e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                throw new RuntimeException("egl not initialized");
407e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            }
408fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy            if (sEglDisplay == null) {
409e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                throw new RuntimeException("eglDisplay not initialized");
410e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            }
411fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy            if (sEglConfig == null) {
412e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                throw new RuntimeException("mEglConfig not initialized");
413e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            }
414fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy            if (Thread.currentThread() != sEglThread) {
415fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy                throw new IllegalStateException("HardwareRenderer cannot be used "
416fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy                        + "from multiple threads");
417fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy            }
418e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
4192d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy            /*
420e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy             *  The window size has changed, so we need to create a new
421e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy             *  surface.
4222d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy             */
423e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            if (mEglSurface != null && mEglSurface != EGL10.EGL_NO_SURFACE) {
424e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                /*
425e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                 * Unbind and destroy the old EGL surface, if
426e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                 * there is one.
427e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                 */
428fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy                sEgl.eglMakeCurrent(sEglDisplay, EGL10.EGL_NO_SURFACE,
429e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                        EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
430fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy                sEgl.eglDestroySurface(sEglDisplay, mEglSurface);
431e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            }
432e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
433e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            // Create an EGL surface we can render into.
434fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy            mEglSurface = sEgl.eglCreateWindowSurface(sEglDisplay, sEglConfig, holder, null);
435e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
436e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) {
437fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy                int error = sEgl.eglGetError();
438e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                if (error == EGL10.EGL_BAD_NATIVE_WINDOW) {
4397d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                    Log.e(LOG_TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
440e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                    return null;
441e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                }
4425d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                throw new RuntimeException("createWindowSurface failed "
4435d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                        + getEGLErrorString(error));
444e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            }
445e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
4462d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy            /*
4472d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy             * Before we can issue GL commands, we need to make sure
4482d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy             * the context is current and bound to a surface.
4492d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy             */
450fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy            if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, sEglContext)) {
4515d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                throw new RuntimeException("eglMakeCurrent failed "
4525d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                        + getEGLErrorString(sEgl.eglGetError()));
453e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            }
4547d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy
4557d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy            if (RENDER_DIRTY_REGIONS) {
4567d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                if (!GLES20Canvas.preserveBackBuffer()) {
4577d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                    Log.w(LOG_TAG, "Backbuffer cannot be preserved");
4587d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                }
4597d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy            }
460e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
461fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy            return sEglContext.getGL();
4622d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        }
4632d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
464e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
465e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, mGlVersion, EGL10.EGL_NONE };
466e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
467e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            return egl.eglCreateContext(eglDisplay, eglConfig, EGL10.EGL_NO_CONTEXT,
468e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                    mGlVersion != 0 ? attrib_list : null);
469e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        }
470e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
471e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        @Override
472e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        void initializeIfNeeded(int width, int height, View.AttachInfo attachInfo,
473e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                SurfaceHolder holder) {
474e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            if (isRequested()) {
475b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy                checkEglErrors();
476e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                super.initializeIfNeeded(width, height, attachInfo, holder);
477e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            }
478e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        }
479e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
4802d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        @Override
4814caa4ed120a86e855d4d3b6b455c6fb9ca22e365Romain Guy        void destroy(boolean full) {
4824caa4ed120a86e855d4d3b6b455c6fb9ca22e365Romain Guy            if (full && mCanvas != null) {
4834caa4ed120a86e855d4d3b6b455c6fb9ca22e365Romain Guy                mCanvas = null;
4844caa4ed120a86e855d4d3b6b455c6fb9ca22e365Romain Guy            }
4854caa4ed120a86e855d4d3b6b455c6fb9ca22e365Romain Guy
486fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy            if (!isEnabled() || mDestroyed) return;
487fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy
488fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy            mDestroyed = true;
489e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
490fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy            sEgl.eglMakeCurrent(sEglDisplay, EGL10.EGL_NO_SURFACE,
4912d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy                    EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
492fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy            sEgl.eglDestroySurface(sEglDisplay, mEglSurface);
4932d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
4942d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy            mEglSurface = null;
495e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            mGl = null;
496fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy
4972d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy            setEnabled(false);
498fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        }
499fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy
5002d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        @Override
501fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        void setup(int width, int height) {
502fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy            mCanvas.setViewport(width, height);
503e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        }
5047d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy
505e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        boolean canDraw() {
506e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            return mGl != null && mCanvas != null;
507e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        }
508e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
5097d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy        void onPreDraw(Rect dirty) {
510e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        }
511e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
512b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy        void onPostDraw() {
513b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy        }
514b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy
515e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        /**
516d10cd5765a2b706fc174f16b951d6b0a5d3740d3Romain Guy         * Defines the EGL configuration for this renderer.
517e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy         *
518e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy         * @return An {@link android.view.HardwareRenderer.GlRenderer.EglConfigChooser}.
519e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy         */
520e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        EglConfigChooser getConfigChooser(int glVersion) {
521fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy            return new ComponentSizeChooser(glVersion, 8, 8, 8, 8, 0, 0);
5222d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        }
5232d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy
5242d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        @Override
5257d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy        void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks,
5267d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                Rect dirty) {
527e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            if (canDraw()) {
5287d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                //noinspection PointlessBooleanExpression,ConstantConditions
5297d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                if (!HardwareRenderer.RENDER_DIRTY_REGIONS) {
5307d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                    dirty = null;
5317d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                }
5327d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy
5332d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy                attachInfo.mDrawingTime = SystemClock.uptimeMillis();
5342d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy                attachInfo.mIgnoreDirtyState = true;
5352d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy                view.mPrivateFlags |= View.DRAWN;
5369a40babc62416259d18783ce8c03c00042ec317bRomain Guy
5379a40babc62416259d18783ce8c03c00042ec317bRomain Guy                long startTime;
5389a40babc62416259d18783ce8c03c00042ec317bRomain Guy                if (ViewDebug.DEBUG_PROFILE_DRAWING) {
5399a40babc62416259d18783ce8c03c00042ec317bRomain Guy                    startTime = SystemClock.elapsedRealtime();
5409a40babc62416259d18783ce8c03c00042ec317bRomain Guy                }
541e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
542d88f54c5c4ce59585b8b9e6009836f14c00be743Romain Guy                final int surfaceState = checkCurrent();
543d88f54c5c4ce59585b8b9e6009836f14c00be743Romain Guy                if (surfaceState != SURFACE_STATE_ERROR) {
544d88f54c5c4ce59585b8b9e6009836f14c00be743Romain Guy                    // We had to change the current surface and/or context, redraw everything
545d88f54c5c4ce59585b8b9e6009836f14c00be743Romain Guy                    if (surfaceState == SURFACE_STATE_UPDATED) {
546d88f54c5c4ce59585b8b9e6009836f14c00be743Romain Guy                        dirty = null;
547d88f54c5c4ce59585b8b9e6009836f14c00be743Romain Guy                    }
548d88f54c5c4ce59585b8b9e6009836f14c00be743Romain Guy
5497d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                    onPreDraw(dirty);
55062687ec12cb8e0b1d4044a235b1387b9a8c3b4b4Romain Guy
551daf98e941e140e8739458126640183b9f296a2abChet Haase                    HardwareCanvas canvas = mCanvas;
552daf98e941e140e8739458126640183b9f296a2abChet Haase                    attachInfo.mHardwareCanvas = canvas;
5537d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy
554b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy                    int saveCount = canvas.save();
555b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy                    callbacks.onHardwarePreDraw(canvas);
556daf98e941e140e8739458126640183b9f296a2abChet Haase
557b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy                    try {
558daf98e941e140e8739458126640183b9f296a2abChet Haase                        view.mRecreateDisplayList =
559daf98e941e140e8739458126640183b9f296a2abChet Haase                                (view.mPrivateFlags & View.INVALIDATED) == View.INVALIDATED;
560daf98e941e140e8739458126640183b9f296a2abChet Haase                        view.mPrivateFlags &= ~View.INVALIDATED;
5617d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy
562daf98e941e140e8739458126640183b9f296a2abChet Haase                        DisplayList displayList = view.getDisplayList();
563daf98e941e140e8739458126640183b9f296a2abChet Haase                        if (displayList != null) {
564daf98e941e140e8739458126640183b9f296a2abChet Haase                            if (canvas.drawDisplayList(displayList)) {
565daf98e941e140e8739458126640183b9f296a2abChet Haase                                view.invalidate();
566daf98e941e140e8739458126640183b9f296a2abChet Haase                            }
567daf98e941e140e8739458126640183b9f296a2abChet Haase                        } else {
568daf98e941e140e8739458126640183b9f296a2abChet Haase                            // Shouldn't reach here
569daf98e941e140e8739458126640183b9f296a2abChet Haase                            view.draw(canvas);
570daf98e941e140e8739458126640183b9f296a2abChet Haase                        }
5717d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy
5727d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                        if (DEBUG_DIRTY_REGION) {
5737d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                            if (mDebugPaint == null) {
5747d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                                mDebugPaint = new Paint();
5757d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                                mDebugPaint.setColor(0x7fff0000);
5767d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                            }
5777d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                            if (dirty != null && (mFrameCount++ & 1) == 0) {
5787d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                                canvas.drawRect(dirty, mDebugPaint);
5797d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                            }
5807d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                        }
581b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy                    } finally {
582b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy                        callbacks.onHardwarePostDraw(canvas);
583b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy                        canvas.restoreToCount(saveCount);
584daf98e941e140e8739458126640183b9f296a2abChet Haase                        view.mRecreateDisplayList = false;
585b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy                    }
586daf98e941e140e8739458126640183b9f296a2abChet Haase
587b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy                    onPostDraw();
588daf98e941e140e8739458126640183b9f296a2abChet Haase
589b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy                    if (ViewDebug.DEBUG_PROFILE_DRAWING) {
590b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy                        EventLog.writeEvent(60000, SystemClock.elapsedRealtime() - startTime);
591b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy                    }
592b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy
593b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy                    attachInfo.mIgnoreDirtyState = false;
594b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy
595b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy                    sEgl.eglSwapBuffers(sEglDisplay, mEglSurface);
596b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy                    checkEglErrors();
5979a40babc62416259d18783ce8c03c00042ec317bRomain Guy                }
5982d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy            }
5992d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        }
600d88f54c5c4ce59585b8b9e6009836f14c00be743Romain Guy
601d88f54c5c4ce59585b8b9e6009836f14c00be743Romain Guy        private int checkCurrent() {
602fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy            // TODO: Don't check the current context when we have one per UI thread
603fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy            // TODO: Use a threadlocal flag to know whether the surface has changed
604fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy            if (sEgl.eglGetCurrentContext() != sEglContext ||
605fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy                    sEgl.eglGetCurrentSurface(EGL10.EGL_DRAW) != mEglSurface) {
606fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy                if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, sEglContext)) {
6079745fae73b584f3e9a9c304098ed9b11f506e93bRomain Guy                    fallback(true);
6089745fae73b584f3e9a9c304098ed9b11f506e93bRomain Guy                    Log.e(LOG_TAG, "eglMakeCurrent failed " +
6099745fae73b584f3e9a9c304098ed9b11f506e93bRomain Guy                            getEGLErrorString(sEgl.eglGetError()));
610d88f54c5c4ce59585b8b9e6009836f14c00be743Romain Guy                    return SURFACE_STATE_ERROR;
611d88f54c5c4ce59585b8b9e6009836f14c00be743Romain Guy                } else {
612d88f54c5c4ce59585b8b9e6009836f14c00be743Romain Guy                    return SURFACE_STATE_UPDATED;
613fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy                }
614fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy            }
615d88f54c5c4ce59585b8b9e6009836f14c00be743Romain Guy            return SURFACE_STATE_SUCCESS;
616fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        }
617fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy
618e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        static abstract class EglConfigChooser {
619e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            final int[] mConfigSpec;
620e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            private final int mGlVersion;
621e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
622e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            EglConfigChooser(int glVersion, int[] configSpec) {
623e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                mGlVersion = glVersion;
624e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                mConfigSpec = filterConfigSpec(configSpec);
625e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            }
626e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
627e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
628f86ef57f8bcd8ba43ce222ec6a8b4f67d3600640Romain Guy                int[] index = new int[1];
629f86ef57f8bcd8ba43ce222ec6a8b4f67d3600640Romain Guy                if (!egl.eglChooseConfig(display, mConfigSpec, null, 0, index)) {
6305d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                    throw new IllegalArgumentException("eglChooseConfig failed "
6315d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                            + getEGLErrorString(egl.eglGetError()));
632e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                }
633e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
634f86ef57f8bcd8ba43ce222ec6a8b4f67d3600640Romain Guy                int numConfigs = index[0];
635e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                if (numConfigs <= 0) {
636f86ef57f8bcd8ba43ce222ec6a8b4f67d3600640Romain Guy                    throw new IllegalArgumentException("No configs match configSpec");
637e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                }
638e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
639e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                EGLConfig[] configs = new EGLConfig[numConfigs];
640f86ef57f8bcd8ba43ce222ec6a8b4f67d3600640Romain Guy                if (!egl.eglChooseConfig(display, mConfigSpec, configs, numConfigs, index)) {
6415d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                    throw new IllegalArgumentException("eglChooseConfig failed "
6425d3e2ea6f3a02b5bd073887eabfa4f50a59bbcf0Mike Dodd                            + getEGLErrorString(egl.eglGetError()));
643e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                }
644f86ef57f8bcd8ba43ce222ec6a8b4f67d3600640Romain Guy
645e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                EGLConfig config = chooseConfig(egl, display, configs);
646e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                if (config == null) {
647e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                    throw new IllegalArgumentException("No config chosen");
648e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                }
649f86ef57f8bcd8ba43ce222ec6a8b4f67d3600640Romain Guy
650e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                return config;
651e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            }
652e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
653f86ef57f8bcd8ba43ce222ec6a8b4f67d3600640Romain Guy            abstract EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, EGLConfig[] configs);
654e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
655e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            private int[] filterConfigSpec(int[] configSpec) {
656e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                if (mGlVersion != 2) {
657e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                    return configSpec;
658e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                }
659e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                /* We know none of the subclasses define EGL_RENDERABLE_TYPE.
660e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                 * And we know the configSpec is well formed.
661e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                 */
662e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                int len = configSpec.length;
663e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                int[] newConfigSpec = new int[len + 2];
664f86ef57f8bcd8ba43ce222ec6a8b4f67d3600640Romain Guy                System.arraycopy(configSpec, 0, newConfigSpec, 0, len - 1);
665f86ef57f8bcd8ba43ce222ec6a8b4f67d3600640Romain Guy                newConfigSpec[len - 1] = EGL10.EGL_RENDERABLE_TYPE;
666e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                newConfigSpec[len] = 4; /* EGL_OPENGL_ES2_BIT */
667f86ef57f8bcd8ba43ce222ec6a8b4f67d3600640Romain Guy                newConfigSpec[len + 1] = EGL10.EGL_NONE;
668e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                return newConfigSpec;
669e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            }
670e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        }
671e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
672e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        /**
673e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy         * Choose a configuration with exactly the specified r,g,b,a sizes,
674e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy         * and at least the specified depth and stencil sizes.
675e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy         */
676e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        static class ComponentSizeChooser extends EglConfigChooser {
677e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            private int[] mValue;
678e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
679e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            private int mRedSize;
680e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            private int mGreenSize;
681e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            private int mBlueSize;
682e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            private int mAlphaSize;
683e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            private int mDepthSize;
684e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            private int mStencilSize;
685e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
686e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            ComponentSizeChooser(int glVersion, int redSize, int greenSize, int blueSize,
687e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                    int alphaSize, int depthSize, int stencilSize) {
688d88f54c5c4ce59585b8b9e6009836f14c00be743Romain Guy                //noinspection PointlessBitwiseExpression
689e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                super(glVersion, new int[] {
690e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                        EGL10.EGL_RED_SIZE, redSize,
691e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                        EGL10.EGL_GREEN_SIZE, greenSize,
692e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                        EGL10.EGL_BLUE_SIZE, blueSize,
693e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                        EGL10.EGL_ALPHA_SIZE, alphaSize,
694e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                        EGL10.EGL_DEPTH_SIZE, depthSize,
695e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                        EGL10.EGL_STENCIL_SIZE, stencilSize,
6967d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                        EGL_SURFACE_TYPE, EGL10.EGL_WINDOW_BIT |
6977d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                                (RENDER_DIRTY_REGIONS ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0),
698e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                        EGL10.EGL_NONE });
699e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                mValue = new int[1];
700e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                mRedSize = redSize;
701e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                mGreenSize = greenSize;
702e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                mBlueSize = blueSize;
703e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                mAlphaSize = alphaSize;
704e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                mDepthSize = depthSize;
705e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                mStencilSize = stencilSize;
706e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy           }
707e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
708e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            @Override
709e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, EGLConfig[] configs) {
710e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                for (EGLConfig config : configs) {
711e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                    int d = findConfigAttrib(egl, display, config, EGL10.EGL_DEPTH_SIZE, 0);
712e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                    int s = findConfigAttrib(egl, display, config, EGL10.EGL_STENCIL_SIZE, 0);
713f86ef57f8bcd8ba43ce222ec6a8b4f67d3600640Romain Guy                    if (d >= mDepthSize && s >= mStencilSize) {
714e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                        int r = findConfigAttrib(egl, display, config, EGL10.EGL_RED_SIZE, 0);
715e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                        int g = findConfigAttrib(egl, display, config, EGL10.EGL_GREEN_SIZE, 0);
716e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                        int b = findConfigAttrib(egl, display, config, EGL10.EGL_BLUE_SIZE, 0);
717e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                        int a = findConfigAttrib(egl, display, config, EGL10.EGL_ALPHA_SIZE, 0);
7187d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                        boolean backBuffer;
7197d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                        if (RENDER_DIRTY_REGIONS) {
7207d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                            int surfaceType = findConfigAttrib(egl, display, config,
7217d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                                    EGL_SURFACE_TYPE, 0);
7227d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                            backBuffer = (surfaceType & EGL_SWAP_BEHAVIOR_PRESERVED_BIT) != 0;
7237d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                        } else {
7247d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                            backBuffer = true;
7257d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                        }
7267d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                        if (r >= mRedSize && g >= mGreenSize && b >= mBlueSize && a >= mAlphaSize
7277d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy                                && backBuffer) {
728e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                            return config;
729e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                        }
730e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                    }
731e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                }
732e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                return null;
733e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            }
734e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
735f86ef57f8bcd8ba43ce222ec6a8b4f67d3600640Romain Guy            private int findConfigAttrib(EGL10 egl, EGLDisplay display, EGLConfig config,
736f86ef57f8bcd8ba43ce222ec6a8b4f67d3600640Romain Guy                    int attribute, int defaultValue) {
737e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) {
738e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                    return mValue[0];
739e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                }
740e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
741e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy                return defaultValue;
742e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy            }
743f86ef57f8bcd8ba43ce222ec6a8b4f67d3600640Romain Guy        }
744e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy    }
745fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy
746e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy    /**
747e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy     * Hardware renderer using OpenGL ES 2.0.
748e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy     */
749e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy    static class Gl20Renderer extends GlRenderer {
750e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        private GLES20Canvas mGlCanvas;
751e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
752e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        Gl20Renderer(boolean translucent) {
753e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            super(2, translucent);
754e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        }
755e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
7562d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        @Override
757fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        GLES20Canvas createCanvas() {
7586b7bd24659fb175fe1f0e97c86c18969918b496aRomain Guy            return mGlCanvas = new GLES20Canvas(mTranslucent);
759e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        }
760b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy
761b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy        @Override
762b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy        boolean canDraw() {
763b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy            return super.canDraw() && mGlCanvas != null;
764b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy        }
765e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
766e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        @Override
7677d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy        void onPreDraw(Rect dirty) {
7687d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy            mGlCanvas.onPreDraw(dirty);
769e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy        }
770e3924992733234fd7d7a614c165a94e0a2cd6b84Romain Guy
771b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy        @Override
772b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy        void onPostDraw() {
773b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy            mGlCanvas.onPostDraw();
774b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy        }
775b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy
776b051e895ccb696604349c6c5efe7c4747e1d1ab6Romain Guy        @Override
77767f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy        void destroy(boolean full) {
778b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy            try {
779b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy                super.destroy(full);
780b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy            } finally {
781b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy                if (full && mGlCanvas != null) {
782b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy                    mGlCanvas = null;
783b8c0de2c2726f4e8f0029710047efe0c8e6661edRomain Guy                }
78467f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy            }
78567f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy        }
78667f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy
78767f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy        @Override
788daf98e941e140e8739458126640183b9f296a2abChet Haase        DisplayList createDisplayList(View v) {
789daf98e941e140e8739458126640183b9f296a2abChet Haase            return new GLES20DisplayList(v);
790b051e895ccb696604349c6c5efe7c4747e1d1ab6Romain Guy        }
7916c319ca1275c8db892c39b48fc54864c949f9171Romain Guy
7926c319ca1275c8db892c39b48fc54864c949f9171Romain Guy        @Override
7936c319ca1275c8db892c39b48fc54864c949f9171Romain Guy        HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque) {
7946c319ca1275c8db892c39b48fc54864c949f9171Romain Guy            return new GLES20Layer(width, height, isOpaque);
7956c319ca1275c8db892c39b48fc54864c949f9171Romain Guy        }
796b051e895ccb696604349c6c5efe7c4747e1d1ab6Romain Guy
797163935113919a184122b8b3bd672ef08c8df65dcRomain Guy        static HardwareRenderer create(boolean translucent) {
798163935113919a184122b8b3bd672ef08c8df65dcRomain Guy            if (GLES20Canvas.isAvailable()) {
799163935113919a184122b8b3bd672ef08c8df65dcRomain Guy                return new Gl20Renderer(translucent);
8002d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy            }
801163935113919a184122b8b3bd672ef08c8df65dcRomain Guy            return null;
8022d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy        }
8032d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy    }
8042d6145993e19d2bb664766dbaf3c1e9ad3d12cdcRomain Guy}
805