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

Commit a84e02ce authored by Romain Guy's avatar Romain Guy Committed by Android (Google) Code Review
Browse files

Merge "Use only one GL context per process, share chaches."

parents 17b4d9ea fb8b763f
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