Bug 844275 - Move the GfxInfoThread so that it is guaranteed to run to completion before compositor creation. r=Cwiiis

This commit is contained in:
Kartikaya Gupta 2013-02-28 13:28:24 -05:00
parent 8c5695896a
commit f519ef0fcb
4 changed files with 58 additions and 37 deletions

View File

@ -156,8 +156,6 @@ public class GeckoAppShell
private static Handler sGeckoHandler;
public static GfxInfoThread sGfxInfoThread = null;
static ActivityHandlerHelper sActivityHelper = new ActivityHandlerHelper();
/* The Android-side API: API methods that Android calls */
@ -2176,9 +2174,7 @@ public class GeckoAppShell
}
public static String getGfxInfoData() {
String data = sGfxInfoThread.getData();
sGfxInfoThread = null;
return data;
return GfxInfoThread.getData();
}
public static void registerSurfaceTextureFrameListener(Object surfaceTexture, final int id) {

View File

@ -5,7 +5,6 @@
package org.mozilla.gecko;
import org.mozilla.gecko.gfx.GfxInfoThread;
import org.mozilla.gecko.mozglue.GeckoLoader;
import org.mozilla.gecko.util.GeckoEventListener;
@ -92,15 +91,6 @@ public class GeckoThread extends Thread implements GeckoEventListener {
@Override
public void run() {
// Here we start the GfxInfo thread, which will query OpenGL
// system information for Gecko. This must be done early enough that the data will be
// ready by the time it's needed to initialize the LayerManager (it takes about 100 ms
// to obtain). Doing it here seems to have no negative effect on startup time. See bug 766251.
// Starting the GfxInfoThread here from the GeckoThread, ensures that
// the Gecko thread is started first, adding some determinism there.
GeckoAppShell.sGfxInfoThread = new GfxInfoThread();
GeckoAppShell.sGfxInfoThread.start();
String path = initGeckoEnvironment();
Log.w(LOGTAG, "zerdatime " + SystemClock.uptimeMillis() + " - runGecko");

View File

@ -59,6 +59,11 @@ public class GLController {
};
private GLController() {
// Here we start the GfxInfo thread, which will query OpenGL
// system information for Gecko. This must be done early enough that the data will be
// ready by the time it's needed to initialize the compositor (it takes about 100 ms
// to obtain).
GfxInfoThread.startThread();
}
static GLController getInstance(LayerView view) {
@ -115,6 +120,17 @@ public class GLController {
mView.post(new Runnable() {
public void run() {
// If we haven't yet created the compositor, and the GfxInfoThread
// isn't done it's data gathering activities, then postpone creating
// the compositor a little bit more. Don't block though, since this is
// the UI thread we're running on. This conditional also ensures that
// we don't call GfxInfoThread.hasData() once we have created the
// compositor, as that is not allowed (see GfxInfoThread).
if (!mCompositorCreated && !GfxInfoThread.hasData()) {
mView.postDelayed(this, 1);
return;
}
try {
// Re-check mSurfaceValid in case the surface was destroyed between
// where we set it to true above and this runnable getting run.

View File

@ -17,45 +17,66 @@ import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.egl.EGLSurface;
public class GfxInfoThread extends Thread {
private static final String LOGTAG = "GfxInfoThread";
private SynchronousQueue<String> mDataQueue;
private static GfxInfoThread sInstance;
private String mData;
public GfxInfoThread() {
mDataQueue = new SynchronousQueue<String>();
private GfxInfoThread() {
}
private void error(String msg) {
Log.e(LOGTAG, msg);
try {
mDataQueue.put("ERROR\n" + msg + "\n");
} catch (InterruptedException e) {
Log.w(LOGTAG, "Thread interrupted", e);
Thread.currentThread().interrupt();
public static void startThread() {
if (sInstance == null) {
sInstance = new GfxInfoThread();
sInstance.start();
}
}
public static boolean hasData() {
// This should never be called before startThread() or after getData()
// so we know sInstance will be non-null here
synchronized (sInstance) {
return sInstance.mData != null;
}
}
public static String getData() {
// This should be called exactly once after startThread(), so we
// know sInstance will be non-null here
String data = sInstance.getDataImpl();
sInstance = null;
return data;
}
private synchronized void error(String msg) {
Log.e(LOGTAG, msg);
mData = "ERROR\n" + msg + "\n";
notifyAll();
}
private void eglError(EGL10 egl, String msg) {
error(msg + " (EGL error " + Integer.toHexString(egl.eglGetError()) + ")");
}
public String getData() {
String data = mDataQueue.poll();
if (data != null)
return data;
private synchronized String getDataImpl() {
if (mData != null) {
return mData;
}
Log.w(LOGTAG, "We need the GfxInfo data, but it is not yet available. " +
"We have to wait for it, so expect abnormally long startup times. " +
"Please report a Mozilla bug.");
try {
data = mDataQueue.take();
while (mData == null) {
wait();
}
} catch (InterruptedException e) {
Log.w(LOGTAG, "Thread interrupted", e);
Thread.currentThread().interrupt();
}
Log.i(LOGTAG, "GfxInfo data is finally available.");
return data;
return mData;
}
@Override
@ -183,11 +204,9 @@ public class GfxInfoThread extends Thread {
// finally send the data. Notice that we've already freed the EGL resources, so that they don't
// remain there until the data is read.
try {
mDataQueue.put(data);
} catch (InterruptedException e) {
Log.w(LOGTAG, "Thread interrupted", e);
Thread.currentThread().interrupt();
synchronized (this) {
mData = data;
notifyAll();
}
}
}