2012-07-05 07:12:10 -07:00
|
|
|
/* -*- 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/. */
|
|
|
|
|
2012-07-11 11:13:49 -07:00
|
|
|
package org.mozilla.gecko.gfx;
|
2012-07-05 07:12:10 -07:00
|
|
|
|
2012-07-27 17:53:54 -07:00
|
|
|
import android.opengl.GLES20;
|
2012-07-05 07:12:10 -07:00
|
|
|
import android.util.Log;
|
2012-07-27 17:53:54 -07:00
|
|
|
|
2012-07-05 07:12:10 -07:00
|
|
|
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;
|
|
|
|
|
|
|
|
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
|
|
|
|
};
|
2012-07-25 09:13:45 -07:00
|
|
|
|
|
|
|
String noES2SupportMsg = "Maybe this device does not support OpenGL ES2?";
|
|
|
|
|
2012-07-05 07:12:10 -07:00
|
|
|
if (!egl.eglChooseConfig(eglDisplay,
|
|
|
|
configAttribs,
|
|
|
|
null,
|
|
|
|
0,
|
|
|
|
returnedNumberOfConfigs))
|
|
|
|
{
|
2012-07-25 09:13:45 -07:00
|
|
|
eglError(egl, "eglChooseConfig failed to query OpenGL ES2 configs. " +
|
|
|
|
noES2SupportMsg);
|
2012-07-05 07:12:10 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// get the first config
|
|
|
|
int numConfigs = returnedNumberOfConfigs[0];
|
2012-07-11 11:19:58 -07:00
|
|
|
if (numConfigs == 0) {
|
2012-07-25 09:13:45 -07:00
|
|
|
error("eglChooseConfig returned zero OpenGL ES2 configs. " +
|
|
|
|
noES2SupportMsg);
|
2012-07-11 11:19:58 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-07-05 07:12:10 -07:00
|
|
|
EGLConfig[] returnedConfigs = new EGLConfig[numConfigs];
|
|
|
|
if (!egl.eglChooseConfig(eglDisplay,
|
|
|
|
configAttribs,
|
|
|
|
returnedConfigs,
|
|
|
|
numConfigs,
|
|
|
|
returnedNumberOfConfigs))
|
|
|
|
{
|
2012-07-25 09:13:45 -07:00
|
|
|
eglError(egl, "eglChooseConfig failed (listing OpenGL ES2 configs). " +
|
|
|
|
noES2SupportMsg);
|
2012-07-05 07:12:10 -07:00
|
|
|
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) {
|
2012-07-25 09:13:45 -07:00
|
|
|
eglError(egl, "eglCreateContext failed to create a OpenGL ES2 context" +
|
|
|
|
noES2SupportMsg);
|
2012-07-05 07:12:10 -07:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|