Bug 844275 - Drive the layer manager creation from the GLController rather than GetLayerManager. r=Cwiiis

This commit is contained in:
Kartikaya Gupta
2013-02-28 13:28:23 -05:00
parent dc5153f1d7
commit ef9f26fb84
9 changed files with 121 additions and 74 deletions

View File

@@ -5,8 +5,12 @@
package org.mozilla.gecko.gfx;
import org.mozilla.gecko.GeckoApp;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.GeckoEvent;
import org.mozilla.gecko.GeckoThread;
import android.util.Log;
import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGLConfig;
@@ -41,6 +45,7 @@ public class GLController {
private EGL10 mEGL;
private EGLDisplay mEGLDisplay;
private EGLConfig mEGLConfig;
private EGLSurface mEGLSurface;
private static final int LOCAL_EGL_OPENGL_ES2_BIT = 4;
@@ -64,22 +69,11 @@ public class GLController {
return sInstance;
}
/* Wait until we are allowed to use EGL functions on the Surface backing
* this window.
* This function is invoked by JNI */
synchronized void waitForValidSurface() {
while (!mSurfaceValid) {
try {
wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
synchronized void surfaceDestroyed() {
GeckoApp.assertOnUiThread();
mSurfaceValid = false;
notifyAll();
mEGLSurface = null;
// We need to coordinate with Gecko when pausing composition, to ensure
// that Gecko never executes a draw event while the compositor is paused.
@@ -95,13 +89,85 @@ public class GLController {
}
synchronized void surfaceChanged(int newWidth, int newHeight) {
GeckoApp.assertOnUiThread();
mWidth = newWidth;
mHeight = newHeight;
if (mSurfaceValid) {
// We need to make this call even when the compositor isn't currently
// paused (e.g. during an orientation change), to make the compositor
// aware of the changed surface.
resumeCompositor(mWidth, mHeight);
return;
}
mSurfaceValid = true;
notifyAll();
// If we get here, we supposedly have a valid surface where previously we
// did not. So we're going to create the window surface and hold on to it
// until the compositor comes asking for it. However, we can't call
// eglCreateWindowSurface right away because the UI thread isn't *actually*
// done setting up - for some reason Android will send us a surfaceChanged
// notification before the surface is actually ready. So, we need to do the
// call to eglCreateWindowSurface in a runnable posted back to the UI thread
// that will run once this call unwinds all the way out and Android finishes
// doing its thing.
mView.post(new Runnable() {
public void run() {
try {
// Re-check mSurfaceValid in case the surface was destroyed between
// where we set it to true above and this runnable getting run.
// If mSurfaceValid is still true, try to create mEGLSurface. If
// mSurfaceValid is false, leave mEGLSurface as null. So at the end
// of this block mEGLSurface will be null (or EGL_NO_SURFACE) if
// eglCreateWindowSurface failed or if mSurfaceValid changed to false.
if (mSurfaceValid) {
if (mEGL == null) {
initEGL();
}
mEGLSurface = mEGL.eglCreateWindowSurface(mEGLDisplay, mEGLConfig, mView.getNativeWindow(), null);
}
} catch (Exception e) {
Log.e(LOGTAG, "Unable to create window surface", e);
}
if (mEGLSurface == null || mEGLSurface == EGL10.EGL_NO_SURFACE) {
mSurfaceValid = false;
mEGLSurface = null; // normalize EGL_NO_SURFACE to null to simplify later checks
Log.e(LOGTAG, "EGL window surface could not be created: " + getEGLError());
return;
}
// At this point mSurfaceValid is true and mEGLSurface is a valid surface. Try
// to create the compositor if it hasn't been created already.
createCompositor();
}
});
}
void createCompositor() {
GeckoApp.assertOnUiThread();
if (mCompositorCreated) {
// If the compositor has already been created, just resume it instead. We don't need
// to block here because if the surface is destroyed before the compositor grabs it,
// we can handle that gracefully (i.e. the compositor will remain paused).
resumeCompositor(mWidth, mHeight);
return;
}
// Only try to create the compositor if we have a valid surface and gecko is up. When these
// two conditions are satisfied, we can be relatively sure that the compositor creation will
// happen without needing to block anyhwere. Do it with a sync gecko event so that the
// android doesn't have a chance to destroy our surface in between.
if (mEGLSurface != null && GeckoThread.checkLaunchState(GeckoThread.LaunchState.GeckoRunning)) {
GeckoAppShell.sendEventToGeckoSync(GeckoEvent.createCompositorResumeEvent());
}
}
void compositorCreated() {
// This is invoked on the compositor thread, while the java UI thread
// is blocked on the gecko sync event in createCompositor() above
mCompositorCreated = true;
}
@@ -148,30 +214,9 @@ public class GLController {
throw new GLControllerException("No suitable EGL configuration found");
}
/**
* Provides an EGLSurface without assuming ownership of this surface.
* This class does not keep a reference to the provided EGL surface; the
* caller assumes ownership of the surface once it is returned.
* This function is invoked by JNI */
/* This function is invoked by JNI on the compositor thread */
private EGLSurface provideEGLSurface() {
synchronized (this) {
if (!mSurfaceValid) {
return null;
}
}
if (mEGL == null) {
initEGL();
}
Object window = mView.getNativeWindow();
EGLSurface surface = mEGL.eglCreateWindowSurface(mEGLDisplay, mEGLConfig, window, null);
if (surface == null || surface == EGL10.EGL_NO_SURFACE) {
throw new GLControllerException("EGL window surface could not be created! " +
getEGLError());
}
return surface;
return mEGLSurface;
}
private String getEGLError() {