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

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

Merge "Move OpenGL support out of ViewRoot into a new HardwareRenderer class."

parents 9396f6e0 2d614599
Loading
Loading
Loading
Loading
+15 −4
Original line number Diff line number Diff line
@@ -65146,7 +65146,7 @@
 type="android.graphics.Canvas"
 static="false"
 final="false"
 deprecated="not deprecated"
 deprecated="deprecated"
 visibility="public"
>
<parameter name="gl" type="javax.microedition.khronos.opengles.GL">
@@ -66075,7 +66075,7 @@
 synchronized="false"
 static="true"
 final="false"
 deprecated="not deprecated"
 deprecated="deprecated"
 visibility="public"
>
</method>
@@ -66132,7 +66132,7 @@
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 deprecated="deprecated"
 visibility="public"
>
</method>
@@ -66193,6 +66193,17 @@
 visibility="public"
>
</method>
<method name="isHardwareAccelerated"
 return="boolean"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="isOpaque"
 return="boolean"
 abstract="false"
@@ -66506,7 +66517,7 @@
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 deprecated="deprecated"
 visibility="public"
>
<parameter name="width" type="int">
+341 −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.
 */


package android.view;

import android.content.res.CompatibilityInfo;
import android.graphics.Canvas;
import android.os.SystemClock;
import android.util.DisplayMetrics;

import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGL11;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLContext;
import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.egl.EGLSurface;
import javax.microedition.khronos.opengles.GL11;

import static javax.microedition.khronos.opengles.GL10.GL_COLOR_BUFFER_BIT;
import static javax.microedition.khronos.opengles.GL10.GL_SCISSOR_TEST;

/**
 * Interface for rendering a ViewRoot using hardware acceleration.
 * 
 * @hide
 */
abstract class HardwareRenderer {
    private boolean mEnabled;
    private boolean mRequested = true;

    /**
     * Destroys the hardware rendering context.
     */
    abstract void destroy();

    /**
     * Initializes the hardware renderer for the specified surface.
     * 
     * @param holder The holder for the surface to hardware accelerate.
     * 
     * @return True if the initialization was successful, false otherwise.
     */
    abstract boolean initialize(SurfaceHolder holder);

    /**
     * Setup the hardware renderer for drawing. This is called for every
     * frame to draw.
     * 
     * @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);

    /**
     * Draws the specified view.
     * 
     * @param view The view to draw.
     * @param attachInfo AttachInfo tied to the specified view.
     * @param translator Translator used to draw applications in compatibility mode.
     * @param yoff The vertical offset for the drawing.
     * @param scalingRequired Whether drawing should be scaled.
     */
    abstract void draw(View view, View.AttachInfo attachInfo,
            CompatibilityInfo.Translator translator, int yoff, boolean scalingRequired);

    /**
     * Initializes the hardware renderer for the specified surface and setup the
     * renderer for drawing, if needed. This is invoked when the ViewRoot has
     * potentially lost the hardware renderer. The hardware renderer should be
     * reinitialized and setup when the render {@link #isRequested()} and
     * {@link #isEnabled()}.
     * 
     * @param width The width of the drawing surface.
     * @param height The height of the drawing surface.
     * @param attachInfo The 
     * @param holder
     */
    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);
                }
            }
        }        
    }

    /**
     * Creates a hardware renderer using OpenGL.
     * 
     * @param glVersion The version of OpenGL to use (1 for OpenGL 1, 11 for OpenGL 1.1, etc.)
     * 
     * @return A hardware renderer backed by OpenGL.
     */
    static HardwareRenderer createGlRenderer(int glVersion) {
        switch (glVersion) {
            case 1:
                return new Gl10Renderer();
        }
        throw new IllegalArgumentException("Unknown GL version: " + glVersion);
    }

    /**
     * Indicates whether hardware acceleration is currently enabled.
     * 
     * @return True if hardware acceleration is in use, false otherwise.
     */
    boolean isEnabled() {
        return mEnabled;
    }

    /**
     * Indicates whether hardware acceleration is currently enabled.
     * 
     * @param enabled True if the hardware renderer is in use, false otherwise.
     */
    void setEnabled(boolean enabled) {
        mEnabled = enabled;
    }

    /**
     * Indicates whether hardware acceleration is currently request but not
     * necessarily enabled yet.
     * 
     * @return True if requested, false otherwise.
     */
    boolean isRequested() {
        return mRequested;
    }

    /**
     * Indicates whether hardware acceleration is currently request but not
     * necessarily enabled yet.
     * 
     * @return True to request hardware acceleration, false otherwise.
     */
    void setRequested(boolean requested) {
        mRequested = requested;
    }

    /**
     * Hardware renderer using OpenGL ES 1.0.
     */
    @SuppressWarnings({"deprecation"})
    static class Gl10Renderer extends HardwareRenderer {
        private EGL10 mEgl;
        private EGLDisplay mEglDisplay;
        private EGLContext mEglContext;
        private EGLSurface mEglSurface;
        private GL11 mGL;

        private Canvas mGlCanvas;

        private Gl10Renderer() {
        }

        private void initializeGL(SurfaceHolder holder) {
            initializeGLInner(holder);
            int err = mEgl.eglGetError();
            if (err != EGL10.EGL_SUCCESS) {
                destroy();
                setRequested(false);
            }
        }

        private void initializeGLInner(SurfaceHolder holder) {
            final EGL10 egl = (EGL10) EGLContext.getEGL();
            mEgl = egl;
    
            final EGLDisplay eglDisplay = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
            mEglDisplay = eglDisplay;
    
            int[] version = new int[2];
            egl.eglInitialize(eglDisplay, version);
    
            final int[] configSpec = {
                    EGL10.EGL_RED_SIZE,      8,
                    EGL10.EGL_GREEN_SIZE,    8,
                    EGL10.EGL_BLUE_SIZE,     8,
                    EGL10.EGL_DEPTH_SIZE,    0,
                    EGL10.EGL_NONE
            };
            final EGLConfig[] configs = new EGLConfig[1];
            final int[] numConfig = new int[1];
            egl.eglChooseConfig(eglDisplay, configSpec, configs, 1, numConfig);
            final EGLConfig config = configs[0];

            /*
             * Create an OpenGL ES context. This must be done only once, an
             * OpenGL context is a somewhat heavy object.
             */
            final EGLContext context = egl.eglCreateContext(eglDisplay, config,
                    EGL10.EGL_NO_CONTEXT, null);
            mEglContext = context;
    
            /*
             * Create an EGL surface we can render into.
             */
            EGLSurface surface = egl.eglCreateWindowSurface(eglDisplay, config, holder, null);
            mEglSurface = surface;
    
            /*
             * Before we can issue GL commands, we need to make sure
             * the context is current and bound to a surface.
             */
            egl.eglMakeCurrent(eglDisplay, surface, surface, context);
    
            /*
             * Get to the appropriate GL interface.
             * This is simply done by casting the GL context to either
             * GL10 or GL11.
             */
            final GL11 gl = (GL11) context.getGL();
            mGL = gl;
            mGlCanvas = new Canvas(gl);
            setEnabled(true);
        }

        @Override
        void destroy() {
            if (!isEnabled()) return;
            
            // inform skia that the context is gone
            nativeAbandonGlCaches();
    
            mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
                    EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
            mEgl.eglDestroyContext(mEglDisplay, mEglContext);
            mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
            mEgl.eglTerminate(mEglDisplay);

            mEglContext = null;
            mEglSurface = null;
            mEglDisplay = null;
            mEgl = null;
            mGlCanvas = null;
            mGL = null;

            setEnabled(false);
        }
    
        private void checkErrors() {
            if (isEnabled()) {
                int err = mEgl.eglGetError();
                if (err != EGL10.EGL_SUCCESS) {
                    // something bad has happened revert to
                    // normal rendering.
                    destroy();
                    if (err != EGL11.EGL_CONTEXT_LOST) {
                        // we'll try again if it was context lost
                        setRequested(false);
                    }
                }
            }
        }

        @Override
        boolean initialize(SurfaceHolder holder) {
            if (isRequested() && !isEnabled()) {
                initializeGL(holder);
                return mGlCanvas != null;
            }
            return false;
        }

        @Override
        void setup(int width, int height, View.AttachInfo attachInfo) {
            final float scale = attachInfo.mApplicationScale;
            mGlCanvas.setViewport((int) (width * scale + 0.5f), (int) (height * scale + 0.5f));
        }

        @Override
        void draw(View view, View.AttachInfo attachInfo, CompatibilityInfo.Translator translator,
                int yoff, boolean scalingRequired) {

            Canvas canvas = mGlCanvas;
            if (mGL != null && canvas != null) {
                mGL.glDisable(GL_SCISSOR_TEST);
                mGL.glClearColor(0, 0, 0, 0);
                mGL.glClear(GL_COLOR_BUFFER_BIT);
                mGL.glEnable(GL_SCISSOR_TEST);
    
                attachInfo.mDrawingTime = SystemClock.uptimeMillis();
                attachInfo.mIgnoreDirtyState = true;
                view.mPrivateFlags |= View.DRAWN;
    
                int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
                try {
                    canvas.translate(0, -yoff);
                    if (translator != null) {
                        translator.translateCanvas(canvas);
                    }
                    canvas.setScreenDensity(scalingRequired ?
                            DisplayMetrics.DENSITY_DEVICE : 0);
    
                    view.draw(canvas);
    
                } finally {
                    canvas.restoreToCount(saveCount);
                }
    
                attachInfo.mIgnoreDirtyState = false;
    
                mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);
                checkErrors();
            }
        }

        @Override
        void initializeIfNeeded(int width, int height, View.AttachInfo attachInfo,
                SurfaceHolder holder) {

            if (isRequested()) {
                checkErrors();
                super.initializeIfNeeded(width, height, attachInfo, holder);
            }
        }
    }

    // inform Skia to just abandon its texture cache IDs
    // doesn't call glDeleteTextures
    private static native void nativeAbandonGlCaches();    
}
+1 −1
Original line number Diff line number Diff line
@@ -1566,7 +1566,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager

        boolean scalingRequired = false;
        Bitmap cache = null;
        if (canvas.getGL() == null &&
        if (!canvas.isHardwareAccelerated() &&
                (flags & FLAG_CHILDREN_DRAWN_WITH_CACHE) == FLAG_CHILDREN_DRAWN_WITH_CACHE ||
                (flags & FLAG_ALWAYS_DRAWN_WITH_CACHE) == FLAG_ALWAYS_DRAWN_WITH_CACHE) {
            cache = child.getDrawingCache(true);
+9 −194
Original line number Diff line number Diff line
@@ -56,10 +56,6 @@ import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;

import javax.microedition.khronos.egl.*;
import javax.microedition.khronos.opengles.*;
import static javax.microedition.khronos.opengles.GL10.*;

/**
 * The top of a view hierarchy, implementing the needed protocol between View
 * and the WindowManager.  This is for the most part an internal implementation
@@ -264,9 +260,8 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
        mDensity = context.getResources().getDisplayMetrics().densityDpi;

        // Try to enable hardware acceleration if requested
        if ((context.getApplicationInfo().flags &
                ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
            mHwRenderer = new HardwareRenderer();
        if ((context.getApplicationInfo().flags & ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
            mHwRenderer = HardwareRenderer.createGlRenderer(1);
        }
    }

@@ -615,8 +610,6 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
        boolean viewVisibilityChanged = mViewVisibility != viewVisibility
                || mNewSurfaceNeeded;

        float appScale = mAttachInfo.mApplicationScale;

        WindowManager.LayoutParams params = null;
        if (mWindowAttributesChanged) {
            mWindowAttributesChanged = false;
@@ -665,7 +658,7 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
            host.dispatchWindowVisibilityChanged(viewVisibility);
            if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) {
                if (mHwRenderer != null) {
                    mHwRenderer.destroyGL();
                    mHwRenderer.destroy();
                }
            }
            if (viewVisibility == View.GONE) {
@@ -873,7 +866,7 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
                        mPreviousTransparentRegion.setEmpty();

                        if (mHwRenderer != null) {
                            hwIntialized = mHwRenderer.initialize();
                            hwIntialized = mHwRenderer.initialize(mHolder);
                        }
                    }
                } else if (!mSurface.isValid()) {
@@ -952,7 +945,7 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
            }
            
            if (hwIntialized) {
                mHwRenderer.setup(appScale);
                mHwRenderer.setup(mWidth, mHeight, mAttachInfo);
            }

            boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
@@ -1248,9 +1241,9 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
            return;
        }
        
        if (mHwRenderer != null && mHwRenderer.mEnabled) {
        if (mHwRenderer != null && mHwRenderer.isEnabled()) {
            if (!dirty.isEmpty()) {
                mHwRenderer.draw(yoff, scalingRequired);
                mHwRenderer.draw(mView, mAttachInfo, mTranslator, yoff, scalingRequired);
            }

            if (scrolling) {
@@ -1578,7 +1571,7 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
        mAttachInfo.mSurface = null;

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

@@ -1842,7 +1835,7 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
                    ensureTouchModeLocally(inTouchMode);

                    if (mHwRenderer != null) {
                        mHwRenderer.initializeAndSetup();
                        mHwRenderer.initializeIfNeeded(mWidth, mHeight, mAttachInfo, mHolder);
                    }
                }

@@ -3313,183 +3306,5 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
        }
    }

    class HardwareRenderer {
        private EGL10 mEgl;
        private EGLDisplay mEglDisplay;
        private EGLContext mEglContext;
        private EGLSurface mEglSurface;
        private GL11 mGL;

        private Canvas mGlCanvas;

        boolean mEnabled;
        boolean mRequested = true;

        private void initializeGL() {
            initializeGLInner();
            int err = mEgl.eglGetError();
            if (err != EGL10.EGL_SUCCESS) {
                destroyGL();
                mRequested = false;
            }
        }

        private void initializeGLInner() {
            final EGL10 egl = (EGL10) EGLContext.getEGL();
            mEgl = egl;
    
            final EGLDisplay eglDisplay = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
            mEglDisplay = eglDisplay;
    
            int[] version = new int[2];
            egl.eglInitialize(eglDisplay, version);
    
            final int[] configSpec = {
                    EGL10.EGL_RED_SIZE,      8,
                    EGL10.EGL_GREEN_SIZE,    8,
                    EGL10.EGL_BLUE_SIZE,     8,
                    EGL10.EGL_DEPTH_SIZE,    0,
                    EGL10.EGL_NONE
            };
            final EGLConfig[] configs = new EGLConfig[1];
            final int[] numConfig = new int[1];
            egl.eglChooseConfig(eglDisplay, configSpec, configs, 1, numConfig);
            final EGLConfig config = configs[0];

            /*
             * Create an OpenGL ES context. This must be done only once, an
             * OpenGL context is a somewhat heavy object.
             */
            final EGLContext context = egl.eglCreateContext(eglDisplay, config,
                    EGL10.EGL_NO_CONTEXT, null);
            mEglContext = context;
    
            /*
             * Create an EGL surface we can render into.
             */
            EGLSurface surface = egl.eglCreateWindowSurface(eglDisplay, config, mHolder, null);
            mEglSurface = surface;
    
            /*
             * Before we can issue GL commands, we need to make sure
             * the context is current and bound to a surface.
             */
            egl.eglMakeCurrent(eglDisplay, surface, surface, context);
    
            /*
             * Get to the appropriate GL interface.
             * This is simply done by casting the GL context to either
             * GL10 or GL11.
             */
            final GL11 gl = (GL11) context.getGL();
            mGL = gl;
            mGlCanvas = new Canvas(gl);
            mEnabled = true;
        }

        void destroyGL() {
            if (!mEnabled) return;
            
            // inform skia that the context is gone
            nativeAbandonGlCaches();
    
            mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
                    EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
            mEgl.eglDestroyContext(mEglDisplay, mEglContext);
            mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
            mEgl.eglTerminate(mEglDisplay);

            mEglContext = null;
            mEglSurface = null;
            mEglDisplay = null;
            mEgl = null;
            mGlCanvas = null;
            mGL = null;

            mEnabled = false;
        }
    
        private void checkErrors() {
            if (mEnabled) {
                int err = mEgl.eglGetError();
                if (err != EGL10.EGL_SUCCESS) {
                    // something bad has happened revert to
                    // normal rendering.
                    destroyGL();
                    if (err != EGL11.EGL_CONTEXT_LOST) {
                        // we'll try again if it was context lost
                        mRequested = false;
                    }
                }
            }
        }

        boolean initialize() {
            if (mRequested && !mEnabled) {
                initializeGL();
                return mGlCanvas != null;
            }
            return false;
        }

        void setup(float appScale) {
            mGlCanvas.setViewport((int) (mWidth * appScale + 0.5f),
                    (int) (mHeight * appScale + 0.5f));
        }

        void draw(int yoff, boolean scalingRequired) {
            Canvas canvas = mGlCanvas;
            if (mGL != null && canvas != null) {
                mGL.glDisable(GL_SCISSOR_TEST);
                mGL.glClearColor(0, 0, 0, 0);
                mGL.glClear(GL_COLOR_BUFFER_BIT);
                mGL.glEnable(GL_SCISSOR_TEST);
    
                mAttachInfo.mDrawingTime = SystemClock.uptimeMillis();
                mAttachInfo.mIgnoreDirtyState = true;
                mView.mPrivateFlags |= View.DRAWN;
    
                int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
                try {
                    canvas.translate(0, -yoff);
                    if (mTranslator != null) {
                        mTranslator.translateCanvas(canvas);
                    }
                    canvas.setScreenDensity(scalingRequired ?
                            DisplayMetrics.DENSITY_DEVICE : 0);
    
                    mView.draw(canvas);
    
                } finally {
                    canvas.restoreToCount(saveCount);
                }
    
                mAttachInfo.mIgnoreDirtyState = false;
    
                mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);
                checkErrors();
            }
        }

        void initializeAndSetup() {
            if (mRequested) {
                checkErrors();
                // we lost the gl context, so recreate it.
                if (mRequested && !mEnabled) {
                    initializeGL();
                    if (mGlCanvas != null) {
                        float appScale = mAttachInfo.mApplicationScale;
                        mGlCanvas.setViewport((int) (mWidth * appScale + 0.5f),
                                (int) (mHeight * appScale + 0.5f));
                    }
                }
            }
        }
    }
    
    private static native void nativeShowFPS(Canvas canvas, int durationMillis);

    // inform skia to just abandon its texture cache IDs
    // doesn't call glDeleteTextures
    private static native void nativeAbandonGlCaches();
}
+2 −1
Original line number Diff line number Diff line
@@ -131,7 +131,8 @@ LOCAL_SRC_FILES:= \
	android_backup_BackupDataInput.cpp \
	android_backup_BackupDataOutput.cpp \
	android_backup_FileBackupHelperBase.cpp \
	android_backup_BackupHelperDispatcher.cpp
	android_backup_BackupHelperDispatcher.cpp \
	android_view_HardwareRenderer.cpp \

LOCAL_C_INCLUDES += \
	$(JNI_H_INCLUDE) \
Loading