Loading core/java/android/view/HardwareRenderer.java +342 −114 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.content.res.CompatibilityInfo; import android.graphics.Canvas; import android.os.SystemClock; import android.util.DisplayMetrics; import android.util.Log; import javax.microedition.khronos.egl.EGL10; import javax.microedition.khronos.egl.EGL11; Loading @@ -28,6 +29,7 @@ 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.GL; import javax.microedition.khronos.opengles.GL11; import static javax.microedition.khronos.opengles.GL10.GL_COLOR_BUFFER_BIT; Loading @@ -41,6 +43,7 @@ import static javax.microedition.khronos.opengles.GL10.GL_SCISSOR_TEST; abstract class HardwareRenderer { private boolean mEnabled; private boolean mRequested = true; private static final String LOG_TAG = "HardwareRenderer"; /** * Destroys the hardware rendering context. Loading Loading @@ -114,6 +117,8 @@ abstract class HardwareRenderer { switch (glVersion) { case 1: return new Gl10Renderer(); case 2: return new Gl20Renderer(); } throw new IllegalArgumentException("Unknown GL version: " + glVersion); } Loading Loading @@ -156,91 +161,170 @@ abstract class HardwareRenderer { 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; static abstract class GlRenderer extends HardwareRenderer { private static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098; EGL10 mEgl; EGLDisplay mEglDisplay; EGLContext mEglContext; EGLSurface mEglSurface; EGLConfig mEglConfig; GL mGl; Canvas mCanvas; private Canvas mGlCanvas; int mGlVersion; private Gl10Renderer() { GlRenderer(int glVersion) { mGlVersion = glVersion; } /** * Checks for OpenGL errors. If an error has occured, {@link #destroy()} * is invoked and the requested flag is turned off. The error code is * also logged as a warning. */ void checkErrors() { if (isEnabled()) { int error = mEgl.eglGetError(); if (error != EGL10.EGL_SUCCESS) { // something bad has happened revert to // normal rendering. destroy(); if (error != EGL11.EGL_CONTEXT_LOST) { // we'll try again if it was context lost setRequested(false); } Log.w(LOG_TAG, "OpenGL error: " + error); } } } @Override boolean initialize(SurfaceHolder holder) { if (isRequested() && !isEnabled()) { initializeEgl(); mGl = createEglSurface(holder); private void initializeGL(SurfaceHolder holder) { initializeGLInner(holder); if (mGl != null) { int err = mEgl.eglGetError(); if (err != EGL10.EGL_SUCCESS) { destroy(); setRequested(false); } else { mCanvas = createCanvas(); if (mCanvas != null) { setEnabled(true); } else { Log.w(LOG_TAG, "Hardware accelerated Canvas could not be created"); } } return mCanvas != null; } } return false; } private void initializeGLInner(SurfaceHolder holder) { final EGL10 egl = (EGL10) EGLContext.getEGL(); mEgl = egl; abstract Canvas createCanvas(); void initializeEgl() { mEgl = (EGL10) EGLContext.getEGL(); // Get to the default display. mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); final EGLDisplay eglDisplay = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); mEglDisplay = eglDisplay; if (mEglDisplay == EGL10.EGL_NO_DISPLAY) { throw new RuntimeException("eglGetDisplay failed"); } // We can now initialize EGL for that display 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]; if (!mEgl.eglInitialize(mEglDisplay, version)) { throw new RuntimeException("eglInitialize failed"); } mEglConfig = getConfigChooser(mGlVersion).chooseConfig(mEgl, mEglDisplay); /* * Create an OpenGL ES context. This must be done only once, an * OpenGL context is a somewhat heavy object. * Create an EGL context. We want to do this as rarely as we can, because an * EGL context is a somewhat heavy object. */ final EGLContext context = egl.eglCreateContext(eglDisplay, config, EGL10.EGL_NO_CONTEXT, null); mEglContext = context; mEglContext = createContext(mEgl, mEglDisplay, mEglConfig); } GL createEglSurface(SurfaceHolder holder) { // Check preconditions. if (mEgl == null) { throw new RuntimeException("egl not initialized"); } if (mEglDisplay == null) { throw new RuntimeException("eglDisplay not initialized"); } if (mEglConfig == null) { throw new RuntimeException("mEglConfig not initialized"); } /* * Create an EGL surface we can render into. * The window size has changed, so we need to create a new * surface. */ EGLSurface surface = egl.eglCreateWindowSurface(eglDisplay, config, holder, null); mEglSurface = surface; if (mEglSurface != null && mEglSurface != EGL10.EGL_NO_SURFACE) { /* * Before we can issue GL commands, we need to make sure * the context is current and bound to a surface. * Unbind and destroy the old EGL surface, if * there is one. */ egl.eglMakeCurrent(eglDisplay, surface, surface, context); mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); mEgl.eglDestroySurface(mEglDisplay, mEglSurface); } // Create an EGL surface we can render into. mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig, holder, null); if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) { int error = mEgl.eglGetError(); if (error == EGL10.EGL_BAD_NATIVE_WINDOW) { Log.e("EglHelper", "createWindowSurface returned EGL_BAD_NATIVE_WINDOW."); return null; } throw new RuntimeException("createWindowSurface failed"); } /* * Get to the appropriate GL interface. * This is simply done by casting the GL context to either * GL10 or GL11. * Before we can issue GL commands, we need to make sure * the context is current and bound to a surface. */ final GL11 gl = (GL11) context.getGL(); mGL = gl; mGlCanvas = new Canvas(gl); setEnabled(true); if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) { throw new RuntimeException("eglMakeCurrent failed"); } return mEglContext.getGL(); } EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) { int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, mGlVersion, EGL10.EGL_NONE }; return egl.eglCreateContext(eglDisplay, eglConfig, EGL10.EGL_NO_CONTEXT, mGlVersion != 0 ? attrib_list : null); } @Override void initializeIfNeeded(int width, int height, View.AttachInfo attachInfo, SurfaceHolder holder) { if (isRequested()) { checkErrors(); super.initializeIfNeeded(width, height, attachInfo, holder); } } @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); Loading @@ -251,68 +335,57 @@ abstract class HardwareRenderer { mEglSurface = null; mEglDisplay = null; mEgl = null; mGlCanvas = null; mGL = null; mGl = null; mCanvas = 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 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)); } @Override boolean initialize(SurfaceHolder holder) { if (isRequested() && !isEnabled()) { initializeGL(holder); return mGlCanvas != null; boolean canDraw() { return mGl != null && mCanvas != null; } return false; void onPreDraw() { } @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)); /** * Defines the EGL configuration for this renderer. The default configuration * is RGBX, no depth, no stencil. * * @return An {@link android.view.HardwareRenderer.GlRenderer.EglConfigChooser}. * @param glVersion */ EglConfigChooser getConfigChooser(int glVersion) { return new ComponentSizeChooser(glVersion, 8, 8, 8, 0, 0, 0); } @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); if (canDraw()) { attachInfo.mDrawingTime = SystemClock.uptimeMillis(); attachInfo.mIgnoreDirtyState = true; view.mPrivateFlags |= View.DRAWN; onPreDraw(); Canvas canvas = mCanvas; 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); canvas.setScreenDensity(scalingRequired ? DisplayMetrics.DENSITY_DEVICE : 0); view.draw(canvas); } finally { canvas.restoreToCount(saveCount); } Loading @@ -324,18 +397,173 @@ abstract class HardwareRenderer { } } static abstract class EglConfigChooser { final int[] mConfigSpec; private final int mGlVersion; EglConfigChooser(int glVersion, int[] configSpec) { mGlVersion = glVersion; mConfigSpec = filterConfigSpec(configSpec); } EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) { int[] num_config = new int[1]; if (!egl.eglChooseConfig(display, mConfigSpec, null, 0, num_config)) { throw new IllegalArgumentException("eglChooseConfig failed"); } int numConfigs = num_config[0]; if (numConfigs <= 0) { throw new IllegalArgumentException( "No configs match configSpec"); } EGLConfig[] configs = new EGLConfig[numConfigs]; if (!egl.eglChooseConfig(display, mConfigSpec, configs, numConfigs, num_config)) { throw new IllegalArgumentException("eglChooseConfig#2 failed"); } EGLConfig config = chooseConfig(egl, display, configs); if (config == null) { throw new IllegalArgumentException("No config chosen"); } return config; } abstract EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, EGLConfig[] configs); private int[] filterConfigSpec(int[] configSpec) { if (mGlVersion != 2) { return configSpec; } /* We know none of the subclasses define EGL_RENDERABLE_TYPE. * And we know the configSpec is well formed. */ int len = configSpec.length; int[] newConfigSpec = new int[len + 2]; System.arraycopy(configSpec, 0, newConfigSpec, 0, len-1); newConfigSpec[len-1] = EGL10.EGL_RENDERABLE_TYPE; newConfigSpec[len] = 4; /* EGL_OPENGL_ES2_BIT */ newConfigSpec[len+1] = EGL10.EGL_NONE; return newConfigSpec; } } /** * Choose a configuration with exactly the specified r,g,b,a sizes, * and at least the specified depth and stencil sizes. */ static class ComponentSizeChooser extends EglConfigChooser { private int[] mValue; private int mRedSize; private int mGreenSize; private int mBlueSize; private int mAlphaSize; private int mDepthSize; private int mStencilSize; ComponentSizeChooser(int glVersion, int redSize, int greenSize, int blueSize, int alphaSize, int depthSize, int stencilSize) { super(glVersion, new int[] { EGL10.EGL_RED_SIZE, redSize, EGL10.EGL_GREEN_SIZE, greenSize, EGL10.EGL_BLUE_SIZE, blueSize, EGL10.EGL_ALPHA_SIZE, alphaSize, EGL10.EGL_DEPTH_SIZE, depthSize, EGL10.EGL_STENCIL_SIZE, stencilSize, EGL10.EGL_NONE }); mValue = new int[1]; mRedSize = redSize; mGreenSize = greenSize; mBlueSize = blueSize; mAlphaSize = alphaSize; mDepthSize = depthSize; mStencilSize = stencilSize; } @Override void initializeIfNeeded(int width, int height, View.AttachInfo attachInfo, SurfaceHolder holder) { EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, EGLConfig[] configs) { for (EGLConfig config : configs) { int d = findConfigAttrib(egl, display, config, EGL10.EGL_DEPTH_SIZE, 0); int s = findConfigAttrib(egl, display, config, EGL10.EGL_STENCIL_SIZE, 0); if ((d >= mDepthSize) && (s >= mStencilSize)) { int r = findConfigAttrib(egl, display, config, EGL10.EGL_RED_SIZE, 0); 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)) { return config; } } } return null; } if (isRequested()) { checkErrors(); super.initializeIfNeeded(width, height, attachInfo, holder); private int findConfigAttrib(EGL10 egl, EGLDisplay display, EGLConfig config, int attribute, int defaultValue) { if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) { return mValue[0]; } return defaultValue; } } } /** * Hardware renderer using OpenGL ES 2.0. */ static class Gl20Renderer extends GlRenderer { Gl20Renderer() { super(2); } @Override Canvas createCanvas() { return null; } } /** * Hardware renderer using OpenGL ES 1.0. */ @SuppressWarnings({"deprecation"}) static class Gl10Renderer extends GlRenderer { Gl10Renderer() { super(1); } @Override Canvas createCanvas() { return new Canvas(mGl); } @Override void destroy() { if (isEnabled()) { nativeAbandonGlCaches(); } super.destroy(); } @Override void onPreDraw() { GL11 gl = (GL11) mGl; gl.glDisable(GL_SCISSOR_TEST); gl.glClearColor(0, 0, 0, 0); gl.glClear(GL_COLOR_BUFFER_BIT); gl.glEnable(GL_SCISSOR_TEST); } } // inform Skia to just abandon its texture cache IDs // doesn't call glDeleteTextures // Inform Skia to just abandon its texture cache IDs doesn't call glDeleteTextures // Used only by the native Skia OpenGL ES 1.x implementation private static native void nativeAbandonGlCaches(); } Loading
core/java/android/view/HardwareRenderer.java +342 −114 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.content.res.CompatibilityInfo; import android.graphics.Canvas; import android.os.SystemClock; import android.util.DisplayMetrics; import android.util.Log; import javax.microedition.khronos.egl.EGL10; import javax.microedition.khronos.egl.EGL11; Loading @@ -28,6 +29,7 @@ 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.GL; import javax.microedition.khronos.opengles.GL11; import static javax.microedition.khronos.opengles.GL10.GL_COLOR_BUFFER_BIT; Loading @@ -41,6 +43,7 @@ import static javax.microedition.khronos.opengles.GL10.GL_SCISSOR_TEST; abstract class HardwareRenderer { private boolean mEnabled; private boolean mRequested = true; private static final String LOG_TAG = "HardwareRenderer"; /** * Destroys the hardware rendering context. Loading Loading @@ -114,6 +117,8 @@ abstract class HardwareRenderer { switch (glVersion) { case 1: return new Gl10Renderer(); case 2: return new Gl20Renderer(); } throw new IllegalArgumentException("Unknown GL version: " + glVersion); } Loading Loading @@ -156,91 +161,170 @@ abstract class HardwareRenderer { 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; static abstract class GlRenderer extends HardwareRenderer { private static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098; EGL10 mEgl; EGLDisplay mEglDisplay; EGLContext mEglContext; EGLSurface mEglSurface; EGLConfig mEglConfig; GL mGl; Canvas mCanvas; private Canvas mGlCanvas; int mGlVersion; private Gl10Renderer() { GlRenderer(int glVersion) { mGlVersion = glVersion; } /** * Checks for OpenGL errors. If an error has occured, {@link #destroy()} * is invoked and the requested flag is turned off. The error code is * also logged as a warning. */ void checkErrors() { if (isEnabled()) { int error = mEgl.eglGetError(); if (error != EGL10.EGL_SUCCESS) { // something bad has happened revert to // normal rendering. destroy(); if (error != EGL11.EGL_CONTEXT_LOST) { // we'll try again if it was context lost setRequested(false); } Log.w(LOG_TAG, "OpenGL error: " + error); } } } @Override boolean initialize(SurfaceHolder holder) { if (isRequested() && !isEnabled()) { initializeEgl(); mGl = createEglSurface(holder); private void initializeGL(SurfaceHolder holder) { initializeGLInner(holder); if (mGl != null) { int err = mEgl.eglGetError(); if (err != EGL10.EGL_SUCCESS) { destroy(); setRequested(false); } else { mCanvas = createCanvas(); if (mCanvas != null) { setEnabled(true); } else { Log.w(LOG_TAG, "Hardware accelerated Canvas could not be created"); } } return mCanvas != null; } } return false; } private void initializeGLInner(SurfaceHolder holder) { final EGL10 egl = (EGL10) EGLContext.getEGL(); mEgl = egl; abstract Canvas createCanvas(); void initializeEgl() { mEgl = (EGL10) EGLContext.getEGL(); // Get to the default display. mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); final EGLDisplay eglDisplay = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); mEglDisplay = eglDisplay; if (mEglDisplay == EGL10.EGL_NO_DISPLAY) { throw new RuntimeException("eglGetDisplay failed"); } // We can now initialize EGL for that display 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]; if (!mEgl.eglInitialize(mEglDisplay, version)) { throw new RuntimeException("eglInitialize failed"); } mEglConfig = getConfigChooser(mGlVersion).chooseConfig(mEgl, mEglDisplay); /* * Create an OpenGL ES context. This must be done only once, an * OpenGL context is a somewhat heavy object. * Create an EGL context. We want to do this as rarely as we can, because an * EGL context is a somewhat heavy object. */ final EGLContext context = egl.eglCreateContext(eglDisplay, config, EGL10.EGL_NO_CONTEXT, null); mEglContext = context; mEglContext = createContext(mEgl, mEglDisplay, mEglConfig); } GL createEglSurface(SurfaceHolder holder) { // Check preconditions. if (mEgl == null) { throw new RuntimeException("egl not initialized"); } if (mEglDisplay == null) { throw new RuntimeException("eglDisplay not initialized"); } if (mEglConfig == null) { throw new RuntimeException("mEglConfig not initialized"); } /* * Create an EGL surface we can render into. * The window size has changed, so we need to create a new * surface. */ EGLSurface surface = egl.eglCreateWindowSurface(eglDisplay, config, holder, null); mEglSurface = surface; if (mEglSurface != null && mEglSurface != EGL10.EGL_NO_SURFACE) { /* * Before we can issue GL commands, we need to make sure * the context is current and bound to a surface. * Unbind and destroy the old EGL surface, if * there is one. */ egl.eglMakeCurrent(eglDisplay, surface, surface, context); mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); mEgl.eglDestroySurface(mEglDisplay, mEglSurface); } // Create an EGL surface we can render into. mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig, holder, null); if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) { int error = mEgl.eglGetError(); if (error == EGL10.EGL_BAD_NATIVE_WINDOW) { Log.e("EglHelper", "createWindowSurface returned EGL_BAD_NATIVE_WINDOW."); return null; } throw new RuntimeException("createWindowSurface failed"); } /* * Get to the appropriate GL interface. * This is simply done by casting the GL context to either * GL10 or GL11. * Before we can issue GL commands, we need to make sure * the context is current and bound to a surface. */ final GL11 gl = (GL11) context.getGL(); mGL = gl; mGlCanvas = new Canvas(gl); setEnabled(true); if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) { throw new RuntimeException("eglMakeCurrent failed"); } return mEglContext.getGL(); } EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) { int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, mGlVersion, EGL10.EGL_NONE }; return egl.eglCreateContext(eglDisplay, eglConfig, EGL10.EGL_NO_CONTEXT, mGlVersion != 0 ? attrib_list : null); } @Override void initializeIfNeeded(int width, int height, View.AttachInfo attachInfo, SurfaceHolder holder) { if (isRequested()) { checkErrors(); super.initializeIfNeeded(width, height, attachInfo, holder); } } @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); Loading @@ -251,68 +335,57 @@ abstract class HardwareRenderer { mEglSurface = null; mEglDisplay = null; mEgl = null; mGlCanvas = null; mGL = null; mGl = null; mCanvas = 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 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)); } @Override boolean initialize(SurfaceHolder holder) { if (isRequested() && !isEnabled()) { initializeGL(holder); return mGlCanvas != null; boolean canDraw() { return mGl != null && mCanvas != null; } return false; void onPreDraw() { } @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)); /** * Defines the EGL configuration for this renderer. The default configuration * is RGBX, no depth, no stencil. * * @return An {@link android.view.HardwareRenderer.GlRenderer.EglConfigChooser}. * @param glVersion */ EglConfigChooser getConfigChooser(int glVersion) { return new ComponentSizeChooser(glVersion, 8, 8, 8, 0, 0, 0); } @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); if (canDraw()) { attachInfo.mDrawingTime = SystemClock.uptimeMillis(); attachInfo.mIgnoreDirtyState = true; view.mPrivateFlags |= View.DRAWN; onPreDraw(); Canvas canvas = mCanvas; 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); canvas.setScreenDensity(scalingRequired ? DisplayMetrics.DENSITY_DEVICE : 0); view.draw(canvas); } finally { canvas.restoreToCount(saveCount); } Loading @@ -324,18 +397,173 @@ abstract class HardwareRenderer { } } static abstract class EglConfigChooser { final int[] mConfigSpec; private final int mGlVersion; EglConfigChooser(int glVersion, int[] configSpec) { mGlVersion = glVersion; mConfigSpec = filterConfigSpec(configSpec); } EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) { int[] num_config = new int[1]; if (!egl.eglChooseConfig(display, mConfigSpec, null, 0, num_config)) { throw new IllegalArgumentException("eglChooseConfig failed"); } int numConfigs = num_config[0]; if (numConfigs <= 0) { throw new IllegalArgumentException( "No configs match configSpec"); } EGLConfig[] configs = new EGLConfig[numConfigs]; if (!egl.eglChooseConfig(display, mConfigSpec, configs, numConfigs, num_config)) { throw new IllegalArgumentException("eglChooseConfig#2 failed"); } EGLConfig config = chooseConfig(egl, display, configs); if (config == null) { throw new IllegalArgumentException("No config chosen"); } return config; } abstract EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, EGLConfig[] configs); private int[] filterConfigSpec(int[] configSpec) { if (mGlVersion != 2) { return configSpec; } /* We know none of the subclasses define EGL_RENDERABLE_TYPE. * And we know the configSpec is well formed. */ int len = configSpec.length; int[] newConfigSpec = new int[len + 2]; System.arraycopy(configSpec, 0, newConfigSpec, 0, len-1); newConfigSpec[len-1] = EGL10.EGL_RENDERABLE_TYPE; newConfigSpec[len] = 4; /* EGL_OPENGL_ES2_BIT */ newConfigSpec[len+1] = EGL10.EGL_NONE; return newConfigSpec; } } /** * Choose a configuration with exactly the specified r,g,b,a sizes, * and at least the specified depth and stencil sizes. */ static class ComponentSizeChooser extends EglConfigChooser { private int[] mValue; private int mRedSize; private int mGreenSize; private int mBlueSize; private int mAlphaSize; private int mDepthSize; private int mStencilSize; ComponentSizeChooser(int glVersion, int redSize, int greenSize, int blueSize, int alphaSize, int depthSize, int stencilSize) { super(glVersion, new int[] { EGL10.EGL_RED_SIZE, redSize, EGL10.EGL_GREEN_SIZE, greenSize, EGL10.EGL_BLUE_SIZE, blueSize, EGL10.EGL_ALPHA_SIZE, alphaSize, EGL10.EGL_DEPTH_SIZE, depthSize, EGL10.EGL_STENCIL_SIZE, stencilSize, EGL10.EGL_NONE }); mValue = new int[1]; mRedSize = redSize; mGreenSize = greenSize; mBlueSize = blueSize; mAlphaSize = alphaSize; mDepthSize = depthSize; mStencilSize = stencilSize; } @Override void initializeIfNeeded(int width, int height, View.AttachInfo attachInfo, SurfaceHolder holder) { EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, EGLConfig[] configs) { for (EGLConfig config : configs) { int d = findConfigAttrib(egl, display, config, EGL10.EGL_DEPTH_SIZE, 0); int s = findConfigAttrib(egl, display, config, EGL10.EGL_STENCIL_SIZE, 0); if ((d >= mDepthSize) && (s >= mStencilSize)) { int r = findConfigAttrib(egl, display, config, EGL10.EGL_RED_SIZE, 0); 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)) { return config; } } } return null; } if (isRequested()) { checkErrors(); super.initializeIfNeeded(width, height, attachInfo, holder); private int findConfigAttrib(EGL10 egl, EGLDisplay display, EGLConfig config, int attribute, int defaultValue) { if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) { return mValue[0]; } return defaultValue; } } } /** * Hardware renderer using OpenGL ES 2.0. */ static class Gl20Renderer extends GlRenderer { Gl20Renderer() { super(2); } @Override Canvas createCanvas() { return null; } } /** * Hardware renderer using OpenGL ES 1.0. */ @SuppressWarnings({"deprecation"}) static class Gl10Renderer extends GlRenderer { Gl10Renderer() { super(1); } @Override Canvas createCanvas() { return new Canvas(mGl); } @Override void destroy() { if (isEnabled()) { nativeAbandonGlCaches(); } super.destroy(); } @Override void onPreDraw() { GL11 gl = (GL11) mGl; gl.glDisable(GL_SCISSOR_TEST); gl.glClearColor(0, 0, 0, 0); gl.glClear(GL_COLOR_BUFFER_BIT); gl.glEnable(GL_SCISSOR_TEST); } } // inform Skia to just abandon its texture cache IDs // doesn't call glDeleteTextures // Inform Skia to just abandon its texture cache IDs doesn't call glDeleteTextures // Used only by the native Skia OpenGL ES 1.x implementation private static native void nativeAbandonGlCaches(); }