Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fb8b763f authored by Romain Guy's avatar Romain Guy
Browse files

Use only one GL context per process, share chaches.

Change-Id: Ieabaa25338d2f4b8d4fd90e7401ad6e7452eae11
parent a1f1174b
Loading
Loading
Loading
Loading
+16 −7
Original line number Diff line number Diff line
@@ -44,7 +44,7 @@ class GLES20Canvas extends Canvas {
    @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
    private final GL mGl;
    private final boolean mOpaque;
    private final int mRenderer;
    private int mRenderer;
    
    private int mWidth;
    private int mHeight;
@@ -76,16 +76,25 @@ class GLES20Canvas extends Canvas {
        mOpaque = !translucent;

        mRenderer = nCreateRenderer();
        if (mRenderer == 0) {
            throw new IllegalStateException("Could not create GLES20Canvas renderer");
        }
    }
    
    private native int nCreateRenderer();

    @Override
    protected void finalize() throws Throwable {
        try {
            super.finalize();
        } finally {
    /**
     * This method <strong>must</strong> be called before releasing a
     * reference to a GLES20Canvas. This method is responsible for freeing
     * native resources associated with the hardware. Not invoking this
     * method properly can result in memory leaks.
     * 
     * @hide
     */
    public synchronized void destroy() {
        if (mRenderer != 0) {
            nDestroyRenderer(mRenderer);
            mRenderer = 0;
        }
    }

+89 −59
Original line number Diff line number Diff line
@@ -35,9 +35,10 @@ import javax.microedition.khronos.opengles.GL;
 * @hide
 */
public abstract class HardwareRenderer {
    private static final String LOG_TAG = "HardwareRenderer";

    private boolean mEnabled;
    private boolean mRequested = true;
    private static final String LOG_TAG = "HardwareRenderer";

    /**
     * Indicates whether hardware acceleration is available under any form for
@@ -70,9 +71,8 @@ public abstract class HardwareRenderer {
     * 
     * @param width Width of the drawing surface.
     * @param height Height of the drawing surface.
     * @param attachInfo The AttachInfo used to render the ViewRoot. 
     */
    abstract void setup(int width, int height, View.AttachInfo attachInfo);
    abstract void setup(int width, int height);

    /**
     * Draws the specified view.
@@ -96,12 +96,11 @@ public abstract class HardwareRenderer {
     */
    void initializeIfNeeded(int width, int height, View.AttachInfo attachInfo,
            SurfaceHolder holder) {

        if (isRequested()) {
            // We lost the gl context, so recreate it.
            if (!isEnabled()) {
                if (initialize(holder)) {
                    setup(width, height, attachInfo);
                    setup(width, height);
                }
            }
        }        
@@ -165,18 +164,23 @@ public abstract class HardwareRenderer {
    static abstract class GlRenderer extends HardwareRenderer {
        private static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;

        EGL10 mEgl;
        EGLDisplay mEglDisplay;
        EGLContext mEglContext;
        static EGLContext sEglContext;
        static EGL10 sEgl;
        static EGLDisplay sEglDisplay;
        static EGLConfig sEglConfig;

        private static Thread sEglThread;        

        EGLSurface mEglSurface;
        EGLConfig mEglConfig;
        
        GL mGl;
        Canvas mCanvas;
        GLES20Canvas mCanvas;

        final int mGlVersion;
        final boolean mTranslucent;

        private boolean mDestroyed;

        GlRenderer(int glVersion, boolean translucent) {
            mGlVersion = glVersion;
            mTranslucent = translucent;
@@ -189,7 +193,7 @@ public abstract class HardwareRenderer {
         */
        void checkErrors() {
            if (isEnabled()) {
                int error = mEgl.eglGetError();
                int error = sEgl.eglGetError();
                if (error != EGL10.EGL_SUCCESS) {
                    // something bad has happened revert to
                    // normal rendering.
@@ -208,13 +212,17 @@ public abstract class HardwareRenderer {
            if (isRequested() && !isEnabled()) {
                initializeEgl();
                mGl = createEglSurface(holder);
                mDestroyed = false;

                if (mGl != null) {
                    int err = mEgl.eglGetError();
                    int err = sEgl.eglGetError();
                    if (err != EGL10.EGL_SUCCESS) {
                        destroy();
                        setRequested(false);
                    } else {
                        if (mCanvas != null) {
                            destroyCanvas();
                        }
                        mCanvas = createCanvas();
                        if (mCanvas != null) {
                            setEnabled(true);
@@ -229,64 +237,75 @@ public abstract class HardwareRenderer {
            return false;
        }

        abstract Canvas createCanvas();
        private void destroyCanvas() {
            mCanvas.destroy();
            mCanvas = null;
        }

        abstract GLES20Canvas createCanvas();

        void initializeEgl() {
            mEgl = (EGL10) EGLContext.getEGL();
            if (sEglContext != null) return;

            sEglThread = Thread.currentThread();
            sEgl = (EGL10) EGLContext.getEGL();
            
            // Get to the default display.
            mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
            sEglDisplay = sEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
            
            if (mEglDisplay == EGL10.EGL_NO_DISPLAY) {
            if (sEglDisplay == EGL10.EGL_NO_DISPLAY) {
                throw new RuntimeException("eglGetDisplay failed");
            }
            
            // We can now initialize EGL for that display
            int[] version = new int[2];
            if (!mEgl.eglInitialize(mEglDisplay, version)) {
            if (!sEgl.eglInitialize(sEglDisplay, version)) {
                throw new RuntimeException("eglInitialize failed");
            }
            mEglConfig = getConfigChooser(mGlVersion).chooseConfig(mEgl, mEglDisplay);
            sEglConfig = getConfigChooser(mGlVersion).chooseConfig(sEgl, sEglDisplay);
            
            /*
            * Create an EGL context. We want to do this as rarely as we can, because an
            * EGL context is a somewhat heavy object.
            */
            mEglContext = createContext(mEgl, mEglDisplay, mEglConfig);
            sEglContext = createContext(sEgl, sEglDisplay, sEglConfig);
        }

        GL createEglSurface(SurfaceHolder holder) {
            // Check preconditions.
            if (mEgl == null) {
            if (sEgl == null) {
                throw new RuntimeException("egl not initialized");
            }
            if (mEglDisplay == null) {
            if (sEglDisplay == null) {
                throw new RuntimeException("eglDisplay not initialized");
            }
            if (mEglConfig == null) {
            if (sEglConfig == null) {
                throw new RuntimeException("mEglConfig not initialized");
            }
            if (Thread.currentThread() != sEglThread) {
                throw new IllegalStateException("HardwareRenderer cannot be used " 
                        + "from multiple threads");
            }

            /*
             *  The window size has changed, so we need to create a new
             *  surface.
             */
            if (mEglSurface != null && mEglSurface != EGL10.EGL_NO_SURFACE) {

                /*
                 * Unbind and destroy the old EGL surface, if
                 * there is one.
                 */
                mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
                sEgl.eglMakeCurrent(sEglDisplay, EGL10.EGL_NO_SURFACE,
                        EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
                mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
                sEgl.eglDestroySurface(sEglDisplay, mEglSurface);
            }

            // Create an EGL surface we can render into.
            mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig, holder, null);
            mEglSurface = sEgl.eglCreateWindowSurface(sEglDisplay, sEglConfig, holder, null);

            if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) {
                int error = mEgl.eglGetError();
                int error = sEgl.eglGetError();
                if (error == EGL10.EGL_BAD_NATIVE_WINDOW) {
                    Log.e("EglHelper", "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
                    return null;
@@ -298,11 +317,11 @@ public abstract class HardwareRenderer {
             * Before we can issue GL commands, we need to make sure
             * the context is current and bound to a surface.
             */
            if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
            if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, sEglContext)) {
                throw new RuntimeException("eglMakeCurrent failed");
            }

            return mEglContext.getGL();
            return sEglContext.getGL();
        }

        EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
@@ -315,7 +334,6 @@ public abstract class HardwareRenderer {
        @Override
        void initializeIfNeeded(int width, int height, View.AttachInfo attachInfo,
                SurfaceHolder holder) {

            if (isRequested()) {
                checkErrors();
                super.initializeIfNeeded(width, height, attachInfo, holder);
@@ -324,28 +342,34 @@ public abstract class HardwareRenderer {
        
        @Override
        void destroy() {
            if (!isEnabled()) return;
            if (!isEnabled() || mDestroyed) return;

            mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
            mDestroyed = true;

            checkCurrent();
            // Destroy the Canvas first in case it needs to use a GL context
            // to perform its cleanup.
            destroyCanvas();

            sEgl.eglMakeCurrent(sEglDisplay, EGL10.EGL_NO_SURFACE,
                    EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
            mEgl.eglDestroyContext(mEglDisplay, mEglContext);
            mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
            mEgl.eglTerminate(mEglDisplay);
            sEgl.eglDestroySurface(sEglDisplay, mEglSurface);

            mEglContext = null;
            mEglSurface = null;
            mEglDisplay = null;
            mEgl = null;
            mGl = null;
            mCanvas = null;

            // mEgl.eglDestroyContext(mEglDisplay, mEglContext);
            // mEglContext = null;            
            // mEgl.eglTerminate(mEglDisplay);
            // mEgl = null;
            // mEglDisplay = null;

            setEnabled(false);
        }

        @Override
        void setup(int width, int height, View.AttachInfo attachInfo) {
            final float scale = attachInfo.mApplicationScale;
            mCanvas.setViewport((int) (width * scale + 0.5f), (int) (height * scale + 0.5f));
        void setup(int width, int height) {
            mCanvas.setViewport(width, height);
        }
        
        boolean canDraw() {
@@ -363,7 +387,8 @@ public abstract class HardwareRenderer {
         * @param glVersion
         */
        EglConfigChooser getConfigChooser(int glVersion) {
            return new ComponentSizeChooser(glVersion, 8, 8, 8, mTranslucent ? 8 : 0, 0, 0);
            // TODO: Check for mTranslucent here, which means at least 2 EGL contexts
            return new ComponentSizeChooser(glVersion, 8, 8, 8, 8, 0, 0);
        }

        @Override
@@ -373,14 +398,7 @@ public abstract class HardwareRenderer {
                attachInfo.mIgnoreDirtyState = true;
                view.mPrivateFlags |= View.DRAWN;

                // TODO: Don't check the current context when we have one per UI thread
                // TODO: Use a threadlocal flag to know whether the surface has changed
                if (mEgl.eglGetCurrentContext() != mEglContext ||
                        mEgl.eglGetCurrentSurface(EGL10.EGL_DRAW) != mEglSurface) {
                    if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
                        throw new RuntimeException("eglMakeCurrent failed");
                    }
                }
                checkCurrent();

                onPreDraw();

@@ -396,11 +414,22 @@ public abstract class HardwareRenderer {

                attachInfo.mIgnoreDirtyState = false;

                mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);
                sEgl.eglSwapBuffers(sEglDisplay, mEglSurface);
                checkErrors();
            }
        }

        private void checkCurrent() {
            // TODO: Don't check the current context when we have one per UI thread
            // TODO: Use a threadlocal flag to know whether the surface has changed
            if (sEgl.eglGetCurrentContext() != sEglContext ||
                    sEgl.eglGetCurrentSurface(EGL10.EGL_DRAW) != mEglSurface) {
                if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, sEglContext)) {
                    throw new RuntimeException("eglMakeCurrent failed");
                }
            }
        }

        static abstract class EglConfigChooser {
            final int[] mConfigSpec;
            private final int mGlVersion;
@@ -496,7 +525,7 @@ public abstract class HardwareRenderer {
                        int g = findConfigAttrib(egl, display, config, EGL10.EGL_GREEN_SIZE, 0);
                        int b = findConfigAttrib(egl, display, config, EGL10.EGL_BLUE_SIZE, 0);
                        int a = findConfigAttrib(egl, display, config, EGL10.EGL_ALPHA_SIZE, 0);
                        if (r == mRedSize && g == mGreenSize && b == mBlueSize && a >= mAlphaSize) {
                        if (r >= mRedSize && g >= mGreenSize && b >= mBlueSize && a >= mAlphaSize) {
                            return config;
                        }
                    }
@@ -526,8 +555,9 @@ public abstract class HardwareRenderer {
        }

        @Override
        Canvas createCanvas() {
            return mGlCanvas = new GLES20Canvas(mGl, mTranslucent);
        GLES20Canvas createCanvas() {
            // TODO: Pass mTranslucent instead of true
            return mGlCanvas = new GLES20Canvas(mGl, true);
        }

        @Override
+17 −17
Original line number Diff line number Diff line
@@ -251,7 +251,7 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
        mTempRect = new Rect();
        mVisRect = new Rect();
        mWinFrame = new Rect();
        mWindow = new W(this, context);
        mWindow = new W(this);
        mInputMethodCallback = new InputMethodCallback(this);
        mViewVisibility = View.GONE;
        mTransparentRegion = new Region();
@@ -469,6 +469,7 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
            if (attrs != null &&
                    (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0) {
                final boolean translucent = attrs.format != PixelFormat.OPAQUE;
                destroyHardwareRenderer();
                mHwRenderer = HardwareRenderer.createGlRenderer(2, translucent);
            }
        }
@@ -677,9 +678,7 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
            attachInfo.mWindowVisibility = viewVisibility;
            host.dispatchWindowVisibilityChanged(viewVisibility);
            if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) {
                if (mHwRenderer != null) {
                    mHwRenderer.destroy();
                }
                destroyHardwareRenderer();
            }
            if (viewVisibility == View.GONE) {
                // After making a window gone, we will count it as being
@@ -963,7 +962,7 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
            }
            
            if (hwIntialized) {
                mHwRenderer.setup(mWidth, mHeight, mAttachInfo);
                mHwRenderer.setup(mWidth, mHeight);
            }

            boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
@@ -1598,9 +1597,9 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
        mAttachInfo.mRootView = null;
        mAttachInfo.mSurface = null;

        if (mHwRenderer != null) {
            mHwRenderer.destroy();
        }
        destroyHardwareRenderer();
        mHwRenderer = null;
        
        mSurface.release();

        if (mInputChannel != null) {
@@ -1625,6 +1624,12 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
        }
    }

    private void destroyHardwareRenderer() {
        if (mHwRenderer != null) {
            mHwRenderer.destroy();
        }
    }

    void updateConfiguration(Configuration config, boolean force) {
        if (DEBUG_CONFIGURATION) Log.v(TAG,
                "Applying new config to window "
@@ -2734,10 +2739,6 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
    public void childDrawableStateChanged(View child) {
    }

    protected Rect getWindowFrame() {
        return mWinFrame;
    }

    void checkThread() {
        if (mThread != Thread.currentThread()) {
            throw new CalledFromWrongThreadException(
@@ -2816,16 +2817,15 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
    static class W extends IWindow.Stub {
        private final WeakReference<ViewRoot> mViewRoot;

        public W(ViewRoot viewRoot, Context context) {
        W(ViewRoot viewRoot) {
            mViewRoot = new WeakReference<ViewRoot>(viewRoot);
        }

        public void resized(int w, int h, Rect coveredInsets,
                Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
        public void resized(int w, int h, Rect coveredInsets, Rect visibleInsets,
                boolean reportDraw, Configuration newConfig) {
            final ViewRoot viewRoot = mViewRoot.get();
            if (viewRoot != null) {
                viewRoot.dispatchResized(w, h, coveredInsets,
                        visibleInsets, reportDraw, newConfig);
                viewRoot.dispatchResized(w, h, coveredInsets, visibleInsets, reportDraw, newConfig);
            }
        }

+1 −2
Original line number Diff line number Diff line
@@ -34,7 +34,6 @@
#include <SkiaShader.h>
#include <SkiaColorFilter.h>
#include <Rect.h>
#include <ui/Rect.h>

#include "TextLayout.h"

libs/hwui/Caches.h

0 → 100644
+75 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef ANDROID_UI_CACHES_H
#define ANDROID_UI_CACHES_H

#define LOG_TAG "OpenGLRenderer"

#include <utils/Singleton.h>

#include "TextureCache.h"
#include "LayerCache.h"
#include "GradientCache.h"
#include "PatchCache.h"
#include "FontRenderer.h"
#include "ProgramCache.h"
#include "PathCache.h"
#include "TextDropShadowCache.h"

namespace android {
namespace uirenderer {

struct CacheLogger {
    CacheLogger() {
        LOGD("Creating caches");
    }
}; // struct CacheLogger

class Caches: public Singleton<Caches> {
    Caches(): Singleton<Caches>(), blend(false), lastSrcMode(GL_ZERO),
            lastDstMode(GL_ZERO), currentProgram(NULL) {
        dropShadowCache.setFontRenderer(fontRenderer);
    }

    friend class Singleton<Caches>;

    CacheLogger logger;

public:
    bool blend;
    GLenum lastSrcMode;
    GLenum lastDstMode;
    Program* currentProgram;

    TextureCache textureCache;
    LayerCache layerCache;
    GradientCache gradientCache;
    ProgramCache programCache;
    PathCache pathCache;
    PatchCache patchCache;
    TextDropShadowCache dropShadowCache;
    FontRenderer fontRenderer;
}; // class Caches

}; // namespace uirenderer

using namespace uirenderer;
ANDROID_SINGLETON_STATIC_INSTANCE(Caches);

}; // namespace android

#endif // ANDROID_UI_CACHES_H
Loading