зеркало из https://github.com/mozilla/gecko-dev.git
Bug 766251 - 1/5 - GfxInfo on Android: the Java and AndroidBridge parts - r=kats,jrmuizel
This commit is contained in:
Родитель
a84a828387
Коммит
9e50f7cb4b
|
@ -1843,4 +1843,8 @@ public class GeckoAppShell
|
|||
|
||||
public static void notifyWakeLockChanged(String topic, String state) {
|
||||
}
|
||||
|
||||
public static String getGfxInfoData() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -123,6 +123,8 @@ public class GeckoAppShell
|
|||
|
||||
private static Handler sGeckoHandler;
|
||||
|
||||
public static GfxInfoThread sGfxInfoThread = null;
|
||||
|
||||
/* The Android-side API: API methods that Android calls */
|
||||
|
||||
// Initialization methods
|
||||
|
@ -2224,6 +2226,13 @@ public class GeckoAppShell
|
|||
public static void notifyWakeLockChanged(String topic, String state) {
|
||||
GeckoApp.mAppContext.notifyWakeLockChanged(topic, state);
|
||||
}
|
||||
|
||||
public static String getGfxInfoData() {
|
||||
String data = sGfxInfoThread.getData();
|
||||
sGfxInfoThread = null;
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ScreenshotHandler {
|
||||
|
|
|
@ -46,6 +46,16 @@ public class GeckoThread extends Thread {
|
|||
}
|
||||
|
||||
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();
|
||||
|
||||
final GeckoApp app = GeckoApp.mAppContext;
|
||||
|
||||
// At some point while loading the gecko libs our default locale gets set
|
||||
|
|
|
@ -107,6 +107,7 @@ FENNEC_JAVA_FILES = \
|
|||
gfx/DrawTimingQueue.java \
|
||||
gfx/FloatSize.java \
|
||||
gfx/GeckoLayerClient.java \
|
||||
gfx/GfxInfoThread.java \
|
||||
gfx/GLController.java \
|
||||
gfx/ImmutableViewportMetrics.java \
|
||||
gfx/InputConnectionHandler.java \
|
||||
|
|
|
@ -0,0 +1,176 @@
|
|||
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.gecko;
|
||||
|
||||
import android.util.Log;
|
||||
import java.util.concurrent.SynchronousQueue;
|
||||
|
||||
import javax.microedition.khronos.egl.EGL10;
|
||||
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 android.opengl.GLES20;
|
||||
|
||||
public class GfxInfoThread extends Thread {
|
||||
|
||||
private static final String LOGTAG = "GfxInfoThread";
|
||||
|
||||
private SynchronousQueue<String> mDataQueue;
|
||||
|
||||
public GfxInfoThread() {
|
||||
mDataQueue = new SynchronousQueue<String>();
|
||||
}
|
||||
|
||||
private void error(String msg) {
|
||||
Log.e(LOGTAG, msg);
|
||||
try {
|
||||
mDataQueue.put("ERROR\n" + msg + "\n");
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
error("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();
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
Log.i(LOGTAG, "GfxInfo data is finally available.");
|
||||
return data;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
// initialize EGL
|
||||
EGL10 egl = (EGL10) EGLContext.getEGL();
|
||||
EGLDisplay eglDisplay = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
|
||||
|
||||
if (eglDisplay == EGL10.EGL_NO_DISPLAY) {
|
||||
eglError(egl, "eglGetDisplay failed");
|
||||
return;
|
||||
}
|
||||
|
||||
int[] returnedVersion = new int[2];
|
||||
if (!egl.eglInitialize(eglDisplay, returnedVersion)) {
|
||||
eglError(egl, "eglInitialize failed");
|
||||
return;
|
||||
}
|
||||
|
||||
// query number of configs
|
||||
int[] returnedNumberOfConfigs = new int[1];
|
||||
int EGL_OPENGL_ES2_BIT = 4;
|
||||
int[] configAttribs = new int[] {
|
||||
EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
|
||||
EGL10.EGL_NONE
|
||||
};
|
||||
if (!egl.eglChooseConfig(eglDisplay,
|
||||
configAttribs,
|
||||
null,
|
||||
0,
|
||||
returnedNumberOfConfigs))
|
||||
{
|
||||
eglError(egl, "eglChooseConfig failed (querying number of configs)");
|
||||
return;
|
||||
}
|
||||
|
||||
// get the first config
|
||||
int numConfigs = returnedNumberOfConfigs[0];
|
||||
EGLConfig[] returnedConfigs = new EGLConfig[numConfigs];
|
||||
if (!egl.eglChooseConfig(eglDisplay,
|
||||
configAttribs,
|
||||
returnedConfigs,
|
||||
numConfigs,
|
||||
returnedNumberOfConfigs))
|
||||
{
|
||||
eglError(egl, "eglChooseConfig failed (listing configs)");
|
||||
return;
|
||||
}
|
||||
|
||||
EGLConfig eglConfig = returnedConfigs[0];
|
||||
|
||||
// create a ES 2.0 context
|
||||
int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
|
||||
int[] contextAttribs = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };
|
||||
EGLContext eglContext = egl.eglCreateContext(eglDisplay,
|
||||
eglConfig,
|
||||
EGL10.EGL_NO_CONTEXT,
|
||||
contextAttribs);
|
||||
if (eglContext == EGL10.EGL_NO_CONTEXT) {
|
||||
eglError(egl, "eglCreateContext failed");
|
||||
return;
|
||||
}
|
||||
|
||||
// create a surface, necessary to make the context current. Hopefully PBuffers
|
||||
// are well supported enough. Are there other kinds of off-screen surfaces in
|
||||
// Android EGL anyway?
|
||||
int[] surfaceAttribs = new int[] {
|
||||
EGL10.EGL_WIDTH, 16,
|
||||
EGL10.EGL_HEIGHT, 16,
|
||||
EGL10.EGL_NONE
|
||||
};
|
||||
EGLSurface eglSurface = egl.eglCreatePbufferSurface(eglDisplay,
|
||||
eglConfig,
|
||||
surfaceAttribs);
|
||||
if (eglSurface == EGL10.EGL_NO_SURFACE) {
|
||||
eglError(egl, "eglCreatePbufferSurface failed");
|
||||
return;
|
||||
}
|
||||
|
||||
// obtain GL strings, store them in mDataQueue
|
||||
if (!egl.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)) {
|
||||
eglError(egl, "eglMakeCurrent failed");
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
int error = egl.eglGetError();
|
||||
if (error != EGL10.EGL_SUCCESS) {
|
||||
error("EGL error " + Integer.toHexString(error));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
String data =
|
||||
"VENDOR\n" + GLES20.glGetString(GLES20.GL_VENDOR) + "\n" +
|
||||
"RENDERER\n" + GLES20.glGetString(GLES20.GL_RENDERER) + "\n" +
|
||||
"VERSION\n" + GLES20.glGetString(GLES20.GL_VERSION) + "\n";
|
||||
|
||||
{
|
||||
int error = GLES20.glGetError();
|
||||
if (error != GLES20.GL_NO_ERROR) {
|
||||
error("OpenGL error " + Integer.toHexString(error));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// clean up after ourselves. This is especially important as some Android devices
|
||||
// have a very low limit on the global number of GL contexts.
|
||||
egl.eglMakeCurrent(eglDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
|
||||
egl.eglDestroySurface(eglDisplay, eglSurface);
|
||||
egl.eglDestroyContext(eglDisplay, eglContext);
|
||||
// intentionally do not eglTerminate: maybe this will make the next eglInitialize faster?
|
||||
|
||||
// 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) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -185,6 +185,8 @@ AndroidBridge::Init(JNIEnv *jEnv,
|
|||
|
||||
jNotifyWakeLockChanged = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyWakeLockChanged", "(Ljava/lang/String;Ljava/lang/String;)V");
|
||||
|
||||
jGetGfxInfoData = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getGfxInfoData", "()Ljava/lang/String;");
|
||||
|
||||
#ifdef MOZ_JAVA_COMPOSITOR
|
||||
jPumpMessageLoop = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "pumpMessageLoop", "()V");
|
||||
|
||||
|
@ -2326,6 +2328,25 @@ AndroidBridge::NotifyWakeLockChanged(const nsAString& topic, const nsAString& st
|
|||
env->CallStaticVoidMethod(mGeckoAppShellClass, jNotifyWakeLockChanged, jstrTopic, jstrState);
|
||||
}
|
||||
|
||||
void
|
||||
AndroidBridge::GetGfxInfoData(nsACString& aRet)
|
||||
{
|
||||
ALOG_BRIDGE("AndroidBridge::GetGfxInfoData");
|
||||
|
||||
JNIEnv* env = GetJNIEnv();
|
||||
if (!env)
|
||||
return;
|
||||
|
||||
AutoLocalJNIFrame jniFrame(env);
|
||||
jstring jstrRet = static_cast<jstring>
|
||||
(env->CallStaticObjectMethod(mGeckoAppShellClass, jGetGfxInfoData));
|
||||
if (jniFrame.CheckForException())
|
||||
return;
|
||||
|
||||
nsJNIString jniStr(jstrRet, env);
|
||||
CopyUTF16toUTF8(jniStr, aRet);
|
||||
}
|
||||
|
||||
/* attribute nsIAndroidBrowserApp browserApp; */
|
||||
NS_IMETHODIMP nsAndroidBridge::GetBrowserApp(nsIAndroidBrowserApp * *aBrowserApp)
|
||||
{
|
||||
|
|
|
@ -357,6 +357,8 @@ public:
|
|||
|
||||
void NotifyWakeLockChanged(const nsAString& topic, const nsAString& state);
|
||||
|
||||
void GetGfxInfoData(nsACString& aRet);
|
||||
|
||||
protected:
|
||||
static AndroidBridge *sBridge;
|
||||
|
||||
|
@ -478,6 +480,9 @@ protected:
|
|||
jmethodID jPumpMessageLoop;
|
||||
jmethodID jNotifyWakeLockChanged;
|
||||
|
||||
// for GfxInfo (gfx feature detection and blacklisting)
|
||||
jmethodID jGetGfxInfoData;
|
||||
|
||||
// For native surface stuff
|
||||
jclass jSurfaceClass;
|
||||
jfieldID jSurfacePointerField;
|
||||
|
|
Загрузка…
Ссылка в новой задаче