From 039857520b1a03a52051b966d87d587225bdfcc3 Mon Sep 17 00:00:00 2001 From: Romain Guy Date: Mon, 11 Jul 2011 15:33:51 -0700 Subject: Always make GL calls with a valid EGL context. Bug #5010760 Change-Id: If7500ef69683948e727df1406f458f18b11259d1 --- core/java/android/view/HardwareRenderer.java | 43 ++++++++++++++++++++++------ core/java/android/view/ViewAncestor.java | 5 ++-- opengl/libs/EGL/egl.cpp | 5 ++++ 3 files changed, 42 insertions(+), 11 deletions(-) diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java index 1638c74..011e44c 100644 --- a/core/java/android/view/HardwareRenderer.java +++ b/core/java/android/view/HardwareRenderer.java @@ -128,10 +128,19 @@ public abstract class HardwareRenderer { abstract void updateSurface(SurfaceHolder holder) throws Surface.OutOfResourcesException; /** - * Invoked whenever the size of the target surface changes. This will - * not be invoked when the surface is first created. + * This method should be invoked whenever the current hardware renderer + * context should be reset. */ - abstract void preapareSurfaceForResize(); + abstract void invalidate(); + + /** + * This method should be invoked to ensure the hardware renderer is in + * valid state (for instance, to ensure the correct EGL context is bound + * to the current thread.) + * + * @return true if the renderer is now valid, false otherwise + */ + abstract boolean validate(); /** * Setup the hardware renderer for drawing. This is called whenever the @@ -629,11 +638,16 @@ public abstract class HardwareRenderer { } @Override - void preapareSurfaceForResize() { + void invalidate() { // Cancels any existing buffer to ensure we'll get a buffer // of the right size before we call eglSwapBuffers sEgl.eglMakeCurrent(sEglDisplay, EGL10.EGL_NO_SURFACE, - EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); + EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); + } + + @Override + boolean validate() { + return checkCurrent() != SURFACE_STATE_ERROR; } @Override @@ -662,7 +676,7 @@ public abstract class HardwareRenderer { attachInfo.mDrawingTime = SystemClock.uptimeMillis(); view.mPrivateFlags |= View.DRAWN; - + final int surfaceState = checkCurrent(); if (surfaceState != SURFACE_STATE_ERROR) { // We had to change the current surface and/or context, redraw everything @@ -723,10 +737,21 @@ public abstract class HardwareRenderer { } } } - + + /** + * Ensures the currnet EGL context is the one we expect. + * + * @return {@link #SURFACE_STATE_ERROR} if the correct EGL context cannot be made current, + * {@link #SURFACE_STATE_UPDATED} if the EGL context was changed or + * {@link #SURFACE_STATE_SUCCESS} if the EGL context was the correct one + */ private int 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 (sEglThread != Thread.currentThread()) { + throw new IllegalStateException("Hardware acceleration can only be used with a " + + "single UI thread.\nOriginal thread: " + sEglThread + "\n" + + "Current thread: " + Thread.currentThread()); + } + if (!sEglContext.equals(sEgl.eglGetCurrentContext()) || !mEglSurface.equals(sEgl.eglGetCurrentSurface(EGL10.EGL_DRAW))) { if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, sEglContext)) { diff --git a/core/java/android/view/ViewAncestor.java b/core/java/android/view/ViewAncestor.java index c0619a5..b7aea20 100644 --- a/core/java/android/view/ViewAncestor.java +++ b/core/java/android/view/ViewAncestor.java @@ -901,6 +901,7 @@ public final class ViewAncestor extends Handler implements ViewParent, !mAttachInfo.mTurnOffWindowResizeAnim && mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled() && + mAttachInfo.mHardwareRenderer.validate() && lp != null && !PixelFormat.formatHasAlpha(lp.format)) { disposeResizeBuffer(); @@ -1314,10 +1315,10 @@ public final class ViewAncestor extends Handler implements ViewParent, if (hwInitialized || ((windowShouldResize || params != null) && mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled())) { + mAttachInfo.mHardwareRenderer.setup(mWidth, mHeight); if (!hwInitialized) { - mAttachInfo.mHardwareRenderer.preapareSurfaceForResize(); + mAttachInfo.mHardwareRenderer.invalidate(); } - mAttachInfo.mHardwareRenderer.setup(mWidth, mHeight); } if (!mStopped) { diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp index b11db32..ddad2d3 100644 --- a/opengl/libs/EGL/egl.cpp +++ b/opengl/libs/EGL/egl.cpp @@ -31,6 +31,7 @@ #include #include +#include #include #include "egldefs.h" @@ -147,6 +148,10 @@ static int gl_no_context() { if (egl_tls_t::logNoContextCall()) { LOGE("call to OpenGL ES API with no current context " "(logged once per thread)"); + LOGE("call stack before error:"); + CallStack stack; + stack.update(); + stack.dump(); } return 0; } -- cgit v1.1