mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-26 10:10:31 +00:00
b=573181; clean up render path on Android and prepare for GL layers rendering; r=mwu
This commit is contained in:
parent
b2dc7394dc
commit
5f25830c9f
@ -45,15 +45,6 @@ import java.util.concurrent.atomic.*;
|
||||
import java.util.zip.*;
|
||||
import java.nio.*;
|
||||
|
||||
import javax.microedition.khronos.egl.EGL10;
|
||||
import javax.microedition.khronos.egl.EGL11;
|
||||
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 javax.microedition.khronos.opengles.GL;
|
||||
import javax.microedition.khronos.opengles.GL10;
|
||||
|
||||
import android.os.*;
|
||||
import android.app.*;
|
||||
import android.text.*;
|
||||
@ -85,9 +76,6 @@ class GeckoSurfaceView
|
||||
setFocusable(true);
|
||||
setFocusableInTouchMode(true);
|
||||
|
||||
if (!GeckoApp.useSoftwareDrawing)
|
||||
startEgl();
|
||||
|
||||
mWidth = 0;
|
||||
mHeight = 0;
|
||||
mBufferWidth = 0;
|
||||
@ -98,284 +86,6 @@ class GeckoSurfaceView
|
||||
|
||||
protected void finalize() throws Throwable {
|
||||
super.finalize();
|
||||
if (!GeckoApp.useSoftwareDrawing)
|
||||
finishEgl();
|
||||
}
|
||||
|
||||
private static final int EGL_OPENGL_ES2_BIT = 4;
|
||||
private static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
|
||||
|
||||
private void printConfig(EGL10 egl, EGLDisplay display,
|
||||
EGLConfig config) {
|
||||
int[] attributes = {
|
||||
EGL10.EGL_BUFFER_SIZE,
|
||||
EGL10.EGL_ALPHA_SIZE,
|
||||
EGL10.EGL_BLUE_SIZE,
|
||||
EGL10.EGL_GREEN_SIZE,
|
||||
EGL10.EGL_RED_SIZE,
|
||||
EGL10.EGL_DEPTH_SIZE,
|
||||
EGL10.EGL_STENCIL_SIZE,
|
||||
EGL10.EGL_CONFIG_CAVEAT,
|
||||
EGL10.EGL_CONFIG_ID,
|
||||
EGL10.EGL_LEVEL,
|
||||
EGL10.EGL_MAX_PBUFFER_HEIGHT,
|
||||
EGL10.EGL_MAX_PBUFFER_PIXELS,
|
||||
EGL10.EGL_MAX_PBUFFER_WIDTH,
|
||||
EGL10.EGL_NATIVE_RENDERABLE,
|
||||
EGL10.EGL_NATIVE_VISUAL_ID,
|
||||
EGL10.EGL_NATIVE_VISUAL_TYPE,
|
||||
0x3030, // EGL10.EGL_PRESERVED_RESOURCES,
|
||||
EGL10.EGL_SAMPLES,
|
||||
EGL10.EGL_SAMPLE_BUFFERS,
|
||||
EGL10.EGL_SURFACE_TYPE,
|
||||
EGL10.EGL_TRANSPARENT_TYPE,
|
||||
EGL10.EGL_TRANSPARENT_RED_VALUE,
|
||||
EGL10.EGL_TRANSPARENT_GREEN_VALUE,
|
||||
EGL10.EGL_TRANSPARENT_BLUE_VALUE,
|
||||
0x3039, // EGL10.EGL_BIND_TO_TEXTURE_RGB,
|
||||
0x303A, // EGL10.EGL_BIND_TO_TEXTURE_RGBA,
|
||||
0x303B, // EGL10.EGL_MIN_SWAP_INTERVAL,
|
||||
0x303C, // EGL10.EGL_MAX_SWAP_INTERVAL,
|
||||
EGL10.EGL_LUMINANCE_SIZE,
|
||||
EGL10.EGL_ALPHA_MASK_SIZE,
|
||||
EGL10.EGL_COLOR_BUFFER_TYPE,
|
||||
EGL10.EGL_RENDERABLE_TYPE,
|
||||
0x3042 // EGL10.EGL_CONFORMANT
|
||||
};
|
||||
String[] names = {
|
||||
"EGL_BUFFER_SIZE",
|
||||
"EGL_ALPHA_SIZE",
|
||||
"EGL_BLUE_SIZE",
|
||||
"EGL_GREEN_SIZE",
|
||||
"EGL_RED_SIZE",
|
||||
"EGL_DEPTH_SIZE",
|
||||
"EGL_STENCIL_SIZE",
|
||||
"EGL_CONFIG_CAVEAT",
|
||||
"EGL_CONFIG_ID",
|
||||
"EGL_LEVEL",
|
||||
"EGL_MAX_PBUFFER_HEIGHT",
|
||||
"EGL_MAX_PBUFFER_PIXELS",
|
||||
"EGL_MAX_PBUFFER_WIDTH",
|
||||
"EGL_NATIVE_RENDERABLE",
|
||||
"EGL_NATIVE_VISUAL_ID",
|
||||
"EGL_NATIVE_VISUAL_TYPE",
|
||||
"EGL_PRESERVED_RESOURCES",
|
||||
"EGL_SAMPLES",
|
||||
"EGL_SAMPLE_BUFFERS",
|
||||
"EGL_SURFACE_TYPE",
|
||||
"EGL_TRANSPARENT_TYPE",
|
||||
"EGL_TRANSPARENT_RED_VALUE",
|
||||
"EGL_TRANSPARENT_GREEN_VALUE",
|
||||
"EGL_TRANSPARENT_BLUE_VALUE",
|
||||
"EGL_BIND_TO_TEXTURE_RGB",
|
||||
"EGL_BIND_TO_TEXTURE_RGBA",
|
||||
"EGL_MIN_SWAP_INTERVAL",
|
||||
"EGL_MAX_SWAP_INTERVAL",
|
||||
"EGL_LUMINANCE_SIZE",
|
||||
"EGL_ALPHA_MASK_SIZE",
|
||||
"EGL_COLOR_BUFFER_TYPE",
|
||||
"EGL_RENDERABLE_TYPE",
|
||||
"EGL_CONFORMANT"
|
||||
};
|
||||
int[] value = new int[1];
|
||||
for (int i = 0; i < attributes.length; i++) {
|
||||
int attribute = attributes[i];
|
||||
String name = names[i];
|
||||
if ( egl.eglGetConfigAttrib(display, config, attribute, value)) {
|
||||
Log.w("GeckoAppJava", String.format(" %s: %d\n", name, value[0]));
|
||||
} else {
|
||||
Log.w("GeckoAppJava", String.format(" %s: failed\n", name));
|
||||
// while (egl.eglGetError() != EGL10.EGL_SUCCESS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void startEgl() {
|
||||
if (mEgl != null)
|
||||
return;
|
||||
|
||||
mEgl = (EGL10) EGLContext.getEGL();
|
||||
mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
|
||||
|
||||
// initialize egl
|
||||
int[] version = new int[2];
|
||||
mEgl.eglInitialize(mEglDisplay, version);
|
||||
|
||||
// flip this to true to dump all the EGL configs
|
||||
if (false) {
|
||||
int[] cs = { EGL10.EGL_NONE };
|
||||
int[] ptrnum = new int[1];
|
||||
|
||||
mEgl.eglChooseConfig(mEglDisplay, cs, null, 0, ptrnum);
|
||||
|
||||
int num = ptrnum[0];
|
||||
EGLConfig[] confs = new EGLConfig[num];
|
||||
|
||||
mEgl.eglChooseConfig(mEglDisplay, cs, confs, num, ptrnum);
|
||||
|
||||
for (int i = 0; i < num; ++i) {
|
||||
Log.w("GeckoAppJava", "=== EGL config " + i + " ===");
|
||||
printConfig(mEgl, mEglDisplay, confs[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void finishEgl() {
|
||||
if (mEglDisplay != null) {
|
||||
mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
|
||||
EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
|
||||
}
|
||||
|
||||
if (mEglContext != null) {
|
||||
mEgl.eglDestroyContext(mEglDisplay, mEglContext);
|
||||
mEglContext = null;
|
||||
}
|
||||
|
||||
if (mEglSurface != null) {
|
||||
mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
|
||||
mEglSurface = null;
|
||||
}
|
||||
|
||||
if (mEglDisplay != null) {
|
||||
mEgl.eglTerminate(mEglDisplay);
|
||||
mEglDisplay = null;
|
||||
}
|
||||
|
||||
mEglConfig = null;
|
||||
mEgl = null;
|
||||
|
||||
mSurfaceChanged = false;
|
||||
}
|
||||
|
||||
public void chooseEglConfig() {
|
||||
int redBits, greenBits, blueBits, alphaBits;
|
||||
|
||||
// There are some shenanigans here.
|
||||
// We're required to choose an exact EGL config to match
|
||||
// the surface format, or we get an error. However,
|
||||
// on Droid at least, the format is -1, which is PixelFormat.OPAQUE.
|
||||
// That's not a valid format to be reported; that should just be a
|
||||
// valid value for *setFormat*. We have a catch-all case that
|
||||
// assumes 565 for those cases, but it's pretty ugly.
|
||||
|
||||
Log.i("GeckoAppJava", "GeckoView PixelFormat format is " + mFormat);
|
||||
if (mFormat == PixelFormat.RGB_565) {
|
||||
redBits = 5;
|
||||
greenBits = 6;
|
||||
blueBits = 5;
|
||||
alphaBits = 0;
|
||||
} else if (mFormat == PixelFormat.RGB_888 ||
|
||||
mFormat == PixelFormat.RGBX_8888)
|
||||
{
|
||||
redBits = 8;
|
||||
greenBits = 8;
|
||||
blueBits = 8;
|
||||
alphaBits = 0;
|
||||
} else if (mFormat == PixelFormat.RGBA_8888) {
|
||||
redBits = 8;
|
||||
greenBits = 8;
|
||||
blueBits = 8;
|
||||
alphaBits = 8;
|
||||
} else {
|
||||
Log.w("GeckoAppJava", "Unknown PixelFormat for surface (format is " + mFormat + "), assuming 5650!");
|
||||
redBits = 5;
|
||||
greenBits = 6;
|
||||
blueBits = 5;
|
||||
alphaBits = 0;
|
||||
}
|
||||
|
||||
// PowerVR SGX (Droid) seems to really want depth == 24 for
|
||||
// performance, even 0 is slower. However, other platforms,
|
||||
// like Tegra, don't -have- a 24 bit depth config (have 16).
|
||||
// So that's not good. We'll try with 24 first, and if
|
||||
// nothing, then we'll go to 0. I'm not sure what the nexus
|
||||
// one chip wants.
|
||||
|
||||
int[] confSpec = new int[] {
|
||||
// DEPTH_SIZE must be the first pair
|
||||
EGL10.EGL_DEPTH_SIZE, 24,
|
||||
EGL10.EGL_RED_SIZE, redBits,
|
||||
EGL10.EGL_GREEN_SIZE, greenBits,
|
||||
EGL10.EGL_BLUE_SIZE, blueBits,
|
||||
EGL10.EGL_ALPHA_SIZE, alphaBits,
|
||||
EGL10.EGL_STENCIL_SIZE, 0,
|
||||
EGL10.EGL_CONFIG_CAVEAT, EGL10.EGL_NONE,
|
||||
EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
|
||||
EGL10.EGL_NONE };
|
||||
|
||||
// so tortured to pass an int as an out param...
|
||||
int[] ptrNumConfigs = new int[1];
|
||||
mEgl.eglChooseConfig(mEglDisplay, confSpec, null, 0, ptrNumConfigs);
|
||||
|
||||
int numConfigs = ptrNumConfigs[0];
|
||||
|
||||
if (numConfigs == 0) {
|
||||
// twiddle the DEPTH_SIZE value
|
||||
confSpec[1] = 0;
|
||||
Log.i("GeckoAppJava", "Couldn't find any valid EGL configs with 24 bit depth, trying 0.");
|
||||
|
||||
mEgl.eglChooseConfig(mEglDisplay, confSpec, null, 0, ptrNumConfigs);
|
||||
numConfigs = ptrNumConfigs[0];
|
||||
}
|
||||
|
||||
if (numConfigs <= 0) {
|
||||
// couldn't find a config?
|
||||
Log.w("GeckoAppJava", "Couldn't find any valid EGL configs, blindly trying them all!");
|
||||
|
||||
int[] fallbackConfSpec = new int[] {
|
||||
EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
|
||||
EGL10.EGL_NONE };
|
||||
confSpec = fallbackConfSpec;
|
||||
|
||||
mEgl.eglChooseConfig(mEglDisplay, confSpec, null, 0, ptrNumConfigs);
|
||||
numConfigs = ptrNumConfigs[0];
|
||||
|
||||
if (numConfigs == 0) {
|
||||
Log.e("GeckoAppJava", "There aren't any EGL configs available on this system.");
|
||||
finishEgl();
|
||||
mSurfaceValid = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
EGLConfig[] configs = new EGLConfig[numConfigs];
|
||||
mEgl.eglChooseConfig(mEglDisplay, confSpec, configs, numConfigs, ptrNumConfigs);
|
||||
|
||||
// Find the first config that has the exact RGB sizes that we
|
||||
// need for our window surface.
|
||||
int[] ptrVal = new int[1];
|
||||
for (int i = 0; i < configs.length; ++i) {
|
||||
int confRed = -1, confGreen = -1, confBlue = -1, confAlpha = -1;
|
||||
|
||||
if (mEgl.eglGetConfigAttrib(mEglDisplay, configs[i], EGL10.EGL_RED_SIZE, ptrVal))
|
||||
confRed = ptrVal[0];
|
||||
if (mEgl.eglGetConfigAttrib(mEglDisplay, configs[i], EGL10.EGL_GREEN_SIZE, ptrVal))
|
||||
confGreen = ptrVal[0];
|
||||
if (mEgl.eglGetConfigAttrib(mEglDisplay, configs[i], EGL10.EGL_BLUE_SIZE, ptrVal))
|
||||
confBlue = ptrVal[0];
|
||||
if (mEgl.eglGetConfigAttrib(mEglDisplay, configs[i], EGL10.EGL_ALPHA_SIZE, ptrVal))
|
||||
confAlpha = ptrVal[0];
|
||||
|
||||
if (confRed == redBits &&
|
||||
confGreen == greenBits &&
|
||||
confBlue == blueBits &&
|
||||
confAlpha == alphaBits)
|
||||
{
|
||||
mEglConfig = configs[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mEglConfig == null) {
|
||||
Log.w("GeckoAppJava", "Couldn't find EGL config matching colors; using first, hope it works!");
|
||||
mEglConfig = configs[0];
|
||||
}
|
||||
|
||||
Log.i("GeckoAppJava", "====== Chosen config: ======");
|
||||
printConfig(mEgl, mEglDisplay, mEglConfig);
|
||||
|
||||
mEglContext = null;
|
||||
mEglSurface = null;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -397,10 +107,6 @@ class GeckoSurfaceView
|
||||
|
||||
Log.i("GeckoAppJava", "surfaceChanged: fmt: " + format + " dim: " + width + " " + height);
|
||||
|
||||
if (!GeckoApp.useSoftwareDrawing) {
|
||||
chooseEglConfig();
|
||||
}
|
||||
|
||||
// XXX This code doesn't seem to actually get hit
|
||||
if (!GeckoAppShell.sGeckoRunning) {
|
||||
GeckoAppShell.setInitialSize(width, height);
|
||||
@ -478,72 +184,6 @@ class GeckoSurfaceView
|
||||
return DRAW_SOFTWARE;
|
||||
}
|
||||
|
||||
/*
|
||||
* GL rendering
|
||||
*/
|
||||
|
||||
if (mEgl == null || mEglDisplay == null || mEglConfig == null) {
|
||||
Log.e("GeckoAppJava", "beginDrawing called, but EGL was never initialized!");
|
||||
|
||||
mSurfaceLock.unlock();
|
||||
return DRAW_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the surface doesn't exist, or if its dimensions or something else changed,
|
||||
* recreate it.
|
||||
*/
|
||||
if (mEglSurface == null ||
|
||||
mWidth != mBufferWidth ||
|
||||
mHeight != mBufferHeight ||
|
||||
mSurfaceChanged)
|
||||
{
|
||||
if (mEglContext != null) {
|
||||
mEgl.eglDestroyContext(mEglDisplay, mEglContext);
|
||||
mEglContext = null;
|
||||
}
|
||||
|
||||
if (mEglSurface != null)
|
||||
mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
|
||||
|
||||
mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig, getHolder(), null);
|
||||
if (mEglSurface == EGL10.EGL_NO_SURFACE)
|
||||
{
|
||||
Log.e("GeckoAppJava", "eglCreateWindowSurface failed!");
|
||||
mSurfaceValid = false;
|
||||
return DRAW_ERROR;
|
||||
}
|
||||
|
||||
mBufferWidth = mWidth;
|
||||
mBufferHeight = mHeight;
|
||||
|
||||
mSurfaceChanged = false;
|
||||
}
|
||||
|
||||
if (mEglContext == null) {
|
||||
int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 2,
|
||||
EGL10.EGL_NONE };
|
||||
mEglContext = mEgl.eglCreateContext(mEglDisplay, mEglConfig, EGL10.EGL_NO_CONTEXT, attrib_list);
|
||||
if (mEglContext == EGL10.EGL_NO_CONTEXT)
|
||||
{
|
||||
Log.e("GeckoAppJava", "eglCreateContext failed! " + mEgl.eglGetError());
|
||||
mSurfaceValid = false;
|
||||
return DRAW_ERROR;
|
||||
}
|
||||
|
||||
Log.i("GeckoAppJava", "EglContext created");
|
||||
}
|
||||
|
||||
// Hmm, should we issue this makecurrent for each frame?
|
||||
// We'll likely have to, as other bits might switch the context (e.g.
|
||||
// WebGL, video, etc.).
|
||||
|
||||
if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
|
||||
int err = mEgl.eglGetError();
|
||||
Log.e("GeckoAppJava", "eglMakeCurrent failed! " + err);
|
||||
return DRAW_ERROR;
|
||||
}
|
||||
|
||||
return DRAW_GLES_2;
|
||||
}
|
||||
|
||||
@ -608,17 +248,6 @@ class GeckoSurfaceView
|
||||
getHolder().unlockCanvasAndPost(mSoftwareCanvas);
|
||||
mSoftwareCanvas = null;
|
||||
}
|
||||
} else {
|
||||
// If the surface was changed while we were drawing;
|
||||
// don't even bother trying to swap, it won't work,
|
||||
// and may cause further problems. Note that
|
||||
// eglSwapBuffers might also throw an
|
||||
// IllegalArgumentException; we catch that as well.
|
||||
if (!mSurfaceChanged) {
|
||||
mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);
|
||||
if (mEgl.eglGetError() == EGL11.EGL_CONTEXT_LOST)
|
||||
mSurfaceChanged = true;
|
||||
}
|
||||
}
|
||||
} catch (java.lang.IllegalArgumentException ex) {
|
||||
mSurfaceChanged = true;
|
||||
@ -719,13 +348,6 @@ class GeckoSurfaceView
|
||||
ByteBuffer mSoftwareBuffer;
|
||||
Bitmap mSoftwareBitmap;
|
||||
Canvas mSoftwareCanvas;
|
||||
|
||||
// GL rendering
|
||||
EGL10 mEgl;
|
||||
EGLDisplay mEglDisplay;
|
||||
EGLSurface mEglSurface;
|
||||
EGLConfig mEglConfig;
|
||||
EGLContext mEglContext;
|
||||
}
|
||||
|
||||
class GeckoInputConnection
|
||||
|
@ -102,14 +102,18 @@ LayerManagerOGL::~LayerManagerOGL()
|
||||
}
|
||||
|
||||
PRBool
|
||||
LayerManagerOGL::Initialize()
|
||||
LayerManagerOGL::Initialize(GLContext *aExistingContext)
|
||||
{
|
||||
if (aExistingContext) {
|
||||
mGLContext = aExistingContext;
|
||||
} else {
|
||||
mGLContext = sGLContextProvider.CreateForWindow(mWidget);
|
||||
|
||||
if (!mGLContext) {
|
||||
NS_WARNING("Failed to create LayerManagerOGL context");
|
||||
return PR_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
MakeCurrent();
|
||||
|
||||
|
@ -75,6 +75,8 @@ class LayerOGL;
|
||||
* the main thread.
|
||||
*/
|
||||
class THEBES_API LayerManagerOGL : public LayerManager {
|
||||
typedef mozilla::gl::GLContext GLContext;
|
||||
|
||||
public:
|
||||
LayerManagerOGL(nsIWidget *aWidget);
|
||||
virtual ~LayerManagerOGL();
|
||||
@ -85,9 +87,12 @@ public:
|
||||
* to draw to the window. If this method fails the device cannot be used.
|
||||
* This function is not threadsafe.
|
||||
*
|
||||
* \param aExistingContext an existing GL context to use, instead of creating
|
||||
* our own for the widget.
|
||||
*
|
||||
* \return True is initialization was succesful, false when it was not.
|
||||
*/
|
||||
PRBool Initialize();
|
||||
PRBool Initialize(GLContext *aExistingContext = nsnull);
|
||||
|
||||
/**
|
||||
* Sets the clipping region for this layer manager. This is important on
|
||||
@ -167,8 +172,6 @@ public:
|
||||
return static_cast<ColorTextureLayerProgram*>(mPrograms[RGBALayerProgramType]);
|
||||
}
|
||||
|
||||
typedef mozilla::gl::GLContext GLContext;
|
||||
|
||||
GLContext *gl() const { return mGLContext; }
|
||||
|
||||
/*
|
||||
|
@ -65,7 +65,11 @@ typedef Window EGLNativeWindowType;
|
||||
|
||||
#elif defined(ANDROID)
|
||||
|
||||
#define GET_NATIVE_WINDOW(aWidget) (nsnull)
|
||||
#include <android/log.h>
|
||||
#define ALOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gecko" , ## args)
|
||||
|
||||
/* from widget */
|
||||
#include "AndroidBridge.h"
|
||||
|
||||
typedef void *EGLNativeDisplayType;
|
||||
typedef void *EGLNativePixmapType;
|
||||
@ -148,6 +152,11 @@ public:
|
||||
pfnWaitNative fWaitNative;
|
||||
typedef EGLCastToRelevantPtr (*pfnGetProcAddress)(const char *procname);
|
||||
pfnGetProcAddress fGetProcAddress;
|
||||
typedef EGLBoolean (*pfnSwapBuffers)(EGLDisplay dpy, EGLSurface surface);
|
||||
pfnSwapBuffers fSwapBuffers;
|
||||
typedef EGLBoolean (*pfnCopyBuffers)(EGLDisplay dpy, EGLSurface surface,
|
||||
EGLNativePixmapType target);
|
||||
pfnCopyBuffers fCopyBuffers;
|
||||
typedef const GLubyte* (*pfnQueryString)(EGLDisplay, EGLint name);
|
||||
pfnQueryString fQueryString;
|
||||
typedef EGLBoolean (*pfnBindTexImage)(EGLDisplay, EGLSurface surface, EGLint buffer);
|
||||
@ -197,6 +206,8 @@ public:
|
||||
SYMBOL(GetConfigAttrib),
|
||||
SYMBOL(WaitNative),
|
||||
SYMBOL(GetProcAddress),
|
||||
SYMBOL(SwapBuffers),
|
||||
SYMBOL(CopyBuffers),
|
||||
SYMBOL(QueryString),
|
||||
SYMBOL(BindTexImage),
|
||||
SYMBOL(ReleaseTexImage),
|
||||
@ -316,9 +327,9 @@ public:
|
||||
#else
|
||||
succeeded = PR_FALSE;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
} else {
|
||||
succeeded = sEGLLibrary.fMakeCurrent(mDisplay, mSurface, mSurface, mContext);
|
||||
}
|
||||
NS_ASSERTION(succeeded, "Failed to make GL context current!");
|
||||
}
|
||||
|
||||
@ -345,6 +356,11 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
PRBool SwapBuffers()
|
||||
{
|
||||
return sEGLLibrary.fSwapBuffers(mDisplay, mSurface);
|
||||
}
|
||||
|
||||
private:
|
||||
EGLDisplay mDisplay;
|
||||
EGLConfig mConfig;
|
||||
@ -401,13 +417,17 @@ GLContextProvider::CreateForWindow(nsIWidget *aWidget)
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
if (!sEGLLibrary.fBindAPI(LOCAL_EGL_OPENGL_ES_API)) {
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
EGLint attribs[] = {
|
||||
LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_WINDOW_BIT,
|
||||
LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT,
|
||||
|
||||
#ifdef MOZ_GFX_OPTIMIZE_MOBILE
|
||||
LOCAL_EGL_RED_SIZE, 5,
|
||||
LOCAL_EGL_GREEN_SIZE, 6,
|
||||
LOCAL_EGL_BLUE_SIZE, 5,
|
||||
LOCAL_EGL_ALPHA_SIZE, 0,
|
||||
#endif
|
||||
|
||||
LOCAL_EGL_NONE
|
||||
};
|
||||
|
||||
@ -418,11 +438,28 @@ GLContextProvider::CreateForWindow(nsIWidget *aWidget)
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
#ifdef ANDROID
|
||||
// On Android, we have to ask Java to make the eglCreateWindowSurface
|
||||
// call for us. See GLHelpers.java for a description of why.
|
||||
//
|
||||
// We also only have one true "window", so we just use it directly and ignore
|
||||
// what was passed in.
|
||||
surface = mozilla::AndroidBridge::Bridge()->
|
||||
CallEglCreateWindowSurface(display, config,
|
||||
mozilla::AndroidBridge::Bridge()->SurfaceView());
|
||||
#else
|
||||
surface = sEGLLibrary.fCreateWindowSurface(display, config, GET_NATIVE_WINDOW(aWidget), 0);
|
||||
#endif
|
||||
|
||||
if (!surface) {
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
if (!sEGLLibrary.fBindAPI(LOCAL_EGL_OPENGL_ES_API)) {
|
||||
sEGLLibrary.fDestroySurface(display, surface);
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
EGLint cxattribs[] = {
|
||||
LOCAL_EGL_CONTEXT_CLIENT_VERSION, 2,
|
||||
LOCAL_EGL_NONE
|
||||
|
@ -101,6 +101,15 @@ AndroidBridge::Init(JNIEnv *jEnv,
|
||||
jOpenUriExternal = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "openUriExternal", "(Ljava/lang/String;Ljava/lang/String;)Z");
|
||||
jGetMimeTypeFromExtension = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getMimeTypeFromExtension", "(Ljava/lang/String;)Ljava/lang/String;");
|
||||
jMoveTaskToBack = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "moveTaskToBack", "()V");
|
||||
|
||||
|
||||
jEGLContextClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("javax/microedition/khronos/egl/EGLContext"));
|
||||
jEGL10Class = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("javax/microedition/khronos/egl/EGL10"));
|
||||
jEGLSurfaceImplClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("com/google/android/gles_jni/EGLSurfaceImpl"));
|
||||
jEGLContextImplClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("com/google/android/gles_jni/EGLContextImpl"));
|
||||
jEGLConfigImplClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("com/google/android/gles_jni/EGLConfigImpl"));
|
||||
jEGLDisplayImplClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("com/google/android/gles_jni/EGLDisplayImpl"));
|
||||
|
||||
InitAndroidJavaWrappers(jEnv);
|
||||
|
||||
// jEnv should NOT be cached here by anything -- the jEnv here
|
||||
@ -273,6 +282,50 @@ AndroidBridge::SetSurfaceView(jobject obj)
|
||||
mSurfaceView.Init(obj);
|
||||
}
|
||||
|
||||
void *
|
||||
AndroidBridge::CallEglCreateWindowSurface(void *dpy, void *config, AndroidGeckoSurfaceView &sview)
|
||||
{
|
||||
AutoLocalJNIFrame jniFrame;
|
||||
|
||||
/*
|
||||
* This is basically:
|
||||
*
|
||||
* s = EGLContext.getEGL().eglCreateWindowSurface(new EGLDisplayImpl(dpy),
|
||||
* new EGLConfigImpl(config),
|
||||
* view.getHolder(), null);
|
||||
* return s.mEGLSurface;
|
||||
*
|
||||
* We can't do it from java, because the EGLConfigImpl constructor is private.
|
||||
*/
|
||||
|
||||
jobject surfaceHolder = sview.GetSurfaceHolder();
|
||||
if (!surfaceHolder)
|
||||
return nsnull;
|
||||
|
||||
// grab some fields and methods we'll need
|
||||
jmethodID constructConfig = mJNIEnv->GetMethodID(jEGLConfigImplClass, "<init>", "(I)V");
|
||||
jmethodID constructDisplay = mJNIEnv->GetMethodID(jEGLDisplayImplClass, "<init>", "(I)V");
|
||||
|
||||
jmethodID getEgl = mJNIEnv->GetStaticMethodID(jEGLContextClass, "getEGL", "()Ljavax/microedition/khronos/egl/EGL;");
|
||||
jmethodID createWindowSurface = mJNIEnv->GetMethodID(jEGL10Class, "eglCreateWindowSurface", "(Ljavax/microedition/khronos/egl/EGLDisplay;Ljavax/microedition/khronos/egl/EGLConfig;Ljava/lang/Object;[I)Ljavax/microedition/khronos/egl/EGLSurface;");
|
||||
|
||||
jobject egl = mJNIEnv->CallStaticObjectMethod(jEGLContextClass, getEgl);
|
||||
|
||||
jobject jdpy = mJNIEnv->NewObject(jEGLDisplayImplClass, constructDisplay, (int) dpy);
|
||||
jobject jconf = mJNIEnv->NewObject(jEGLConfigImplClass, constructConfig, (int) config);
|
||||
|
||||
// make the call
|
||||
jobject surf = mJNIEnv->CallObjectMethod(egl, createWindowSurface, jdpy, jconf, surfaceHolder, NULL);
|
||||
if (!surf)
|
||||
return nsnull;
|
||||
|
||||
jfieldID sfield = mJNIEnv->GetFieldID(jEGLSurfaceImplClass, "mEGLSurface", "I");
|
||||
|
||||
jint realSurface = mJNIEnv->GetIntField(surf, sfield);
|
||||
|
||||
return (void*) realSurface;
|
||||
}
|
||||
|
||||
// Available for places elsewhere in the code to link to.
|
||||
PRBool
|
||||
mozilla_AndroidBridge_SetMainThread(void *thr)
|
||||
@ -296,4 +349,3 @@ extern "C" JNIEnv * GetJNIForThread()
|
||||
{
|
||||
return mozilla::AndroidBridge::JNIForThread();
|
||||
}
|
||||
|
||||
|
@ -129,6 +129,9 @@ public:
|
||||
int mEntries;
|
||||
};
|
||||
|
||||
/* See GLHelpers.java as to why this is needed */
|
||||
void *CallEglCreateWindowSurface(void *dpy, void *config, AndroidGeckoSurfaceView& surfaceView);
|
||||
|
||||
protected:
|
||||
static AndroidBridge *sBridge;
|
||||
|
||||
@ -162,6 +165,14 @@ protected:
|
||||
jmethodID jOpenUriExternal;
|
||||
jmethodID jGetMimeTypeFromExtension;
|
||||
jmethodID jMoveTaskToBack;
|
||||
|
||||
// stuff we need for CallEglCreateWindowSurface
|
||||
jclass jEGLSurfaceImplClass;
|
||||
jclass jEGLContextImplClass;
|
||||
jclass jEGLConfigImplClass;
|
||||
jclass jEGLDisplayImplClass;
|
||||
jclass jEGLContextClass;
|
||||
jclass jEGL10Class;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -84,6 +84,7 @@ jclass AndroidGeckoSurfaceView::jGeckoSurfaceViewClass = 0;
|
||||
jmethodID AndroidGeckoSurfaceView::jBeginDrawingMethod = 0;
|
||||
jmethodID AndroidGeckoSurfaceView::jEndDrawingMethod = 0;
|
||||
jmethodID AndroidGeckoSurfaceView::jGetSoftwareDrawBufferMethod = 0;
|
||||
jmethodID AndroidGeckoSurfaceView::jGetHolderMethod = 0;
|
||||
|
||||
#define JNI() (AndroidBridge::JNI())
|
||||
|
||||
@ -146,6 +147,7 @@ AndroidGeckoSurfaceView::InitGeckoSurfaceViewClass(JNIEnv *jEnv)
|
||||
jBeginDrawingMethod = getMethod("beginDrawing", "()I");
|
||||
jGetSoftwareDrawBufferMethod = getMethod("getSoftwareDrawBuffer", "()Ljava/nio/ByteBuffer;");
|
||||
jEndDrawingMethod = getMethod("endDrawing", "()V");
|
||||
jGetHolderMethod = getMethod("getHolder", "()Landroid/view/SurfaceHolder;");
|
||||
}
|
||||
|
||||
void
|
||||
@ -378,6 +380,12 @@ AndroidGeckoSurfaceView::GetSoftwareDrawBuffer(int *cap)
|
||||
return (unsigned char*) bp;
|
||||
}
|
||||
|
||||
jobject
|
||||
AndroidGeckoSurfaceView::GetSurfaceHolder()
|
||||
{
|
||||
return JNI()->CallObjectMethod(wrapped_obj, jGetHolderMethod);
|
||||
}
|
||||
|
||||
void
|
||||
AndroidPoint::Init(JNIEnv *jenv, jobject jobj)
|
||||
{
|
||||
|
@ -46,8 +46,10 @@
|
||||
#include "nsRect.h"
|
||||
#include "nsString.h"
|
||||
|
||||
//#define FORCE_ALOG 1
|
||||
|
||||
#ifndef ALOG
|
||||
#ifdef DEBUG
|
||||
#if defined(DEBUG) || defined(FORCE_ALOG)
|
||||
#define ALOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gecko" , ## args)
|
||||
#else
|
||||
#define ALOG(args...)
|
||||
@ -168,11 +170,17 @@ public:
|
||||
int BeginDrawing();
|
||||
unsigned char *GetSoftwareDrawBuffer(int *cap);
|
||||
void EndDrawing();
|
||||
|
||||
// must have a JNI local frame when calling this,
|
||||
// and you'd better know what you're doing
|
||||
jobject GetSurfaceHolder();
|
||||
|
||||
protected:
|
||||
static jclass jGeckoSurfaceViewClass;
|
||||
static jmethodID jBeginDrawingMethod;
|
||||
static jmethodID jEndDrawingMethod;
|
||||
static jmethodID jGetSoftwareDrawBufferMethod;
|
||||
static jmethodID jGetHolderMethod;
|
||||
};
|
||||
|
||||
class AndroidKeyEvent
|
||||
|
@ -51,25 +51,16 @@
|
||||
#include "gfxImageSurface.h"
|
||||
#include "gfxContext.h"
|
||||
|
||||
#include "Layers.h"
|
||||
#include "BasicLayers.h"
|
||||
#include "LayerManagerOGL.h"
|
||||
#include "GLContext.h"
|
||||
#include "GLContextProvider.h"
|
||||
|
||||
#include "nsTArray.h"
|
||||
|
||||
#include "AndroidBridge.h"
|
||||
|
||||
/* OpenGL */
|
||||
#define USE_GLES2
|
||||
|
||||
#ifdef USE_GLES2
|
||||
#include <GLES2/gl2.h>
|
||||
#include <GLES2/gl2ext.h>
|
||||
#else
|
||||
#include <GLES/gl.h>
|
||||
#include <GLES/glext.h>
|
||||
#endif
|
||||
|
||||
#ifndef GL_BGRA_EXT
|
||||
#define GL_BGRA_EXT 0x80E1
|
||||
#endif
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(nsWindow, nsBaseWidget)
|
||||
@ -90,6 +81,9 @@ static nsTArray<nsWindow*> gTopLevelWindows;
|
||||
static nsWindow* gFocusedWindow = nsnull;
|
||||
static PRUint32 gIMEState;
|
||||
|
||||
static nsRefPtr<gl::GLContext> sGLContext;
|
||||
static PRBool sFailedToCreateGLContext = PR_FALSE;
|
||||
|
||||
static nsWindow*
|
||||
TopWindow()
|
||||
{
|
||||
@ -119,7 +113,7 @@ nsWindow::DumpWindows()
|
||||
void
|
||||
nsWindow::DumpWindows(const nsTArray<nsWindow*>& wins, int indent)
|
||||
{
|
||||
for (int i = 0; i < wins.Length(); ++i) {
|
||||
for (PRUint32 i = 0; i < wins.Length(); ++i) {
|
||||
nsWindow *w = wins[i];
|
||||
LogWindow(w, i, indent);
|
||||
DumpWindows(w->mChildren, indent+1);
|
||||
@ -671,15 +665,33 @@ nsWindow::DrawTo(gfxASurface *targetSurface)
|
||||
if (!mIsVisible)
|
||||
return PR_FALSE;
|
||||
|
||||
nsRefPtr<gfxContext> ctx = new gfxContext(targetSurface);
|
||||
|
||||
nsEventStatus status;
|
||||
nsIntRect boundsRect(0, 0, mBounds.width, mBounds.height);
|
||||
|
||||
// Figure out if any of our children cover this widget completely
|
||||
PRInt32 coveringChildIndex = -1;
|
||||
for (PRUint32 i = 0; i < mChildren.Length(); ++i) {
|
||||
if (mChildren[i]->mBounds.IsEmpty())
|
||||
continue;
|
||||
|
||||
if (mChildren[i]->mBounds.Contains(boundsRect)) {
|
||||
coveringChildIndex = PRInt32(i);
|
||||
}
|
||||
}
|
||||
|
||||
// If we have no covering child, then we need to render this.
|
||||
if (coveringChildIndex == -1) {
|
||||
ALOG("nsWindow[%p]::DrawTo no covering child, drawing this", (void*) this);
|
||||
|
||||
switch (GetLayerManager()->GetBackendType()) {
|
||||
case LayerManager::LAYERS_BASIC: {
|
||||
nsRefPtr<gfxContext> ctx = new gfxContext(targetSurface);
|
||||
|
||||
nsPaintEvent event(PR_TRUE, NS_PAINT, this);
|
||||
event.region = boundsRect;
|
||||
{
|
||||
AutoLayerManagerSetup setupLayerManager(this, ctx);
|
||||
nsEventStatus status = DispatchEvent(&event);
|
||||
status = DispatchEvent(&event);
|
||||
}
|
||||
|
||||
// XXX uhh.. we can't just ignore this because we no longer have
|
||||
@ -692,16 +704,52 @@ nsWindow::DrawTo(gfxASurface *targetSurface)
|
||||
// XXX if we got an ignore for the parent, do we still want to draw the children?
|
||||
// We don't really have a good way not to...
|
||||
|
||||
gfxPoint offset = targetSurface->GetDeviceOffset();
|
||||
}
|
||||
break;
|
||||
|
||||
for (PRUint32 i = 0; i < mChildren.Length(); ++i) {
|
||||
case LayerManager::LAYERS_OPENGL: {
|
||||
static_cast<mozilla::layers::LayerManagerOGL*>(GetLayerManager())->
|
||||
SetClippingRegion(nsIntRegion(boundsRect));
|
||||
|
||||
nsPaintEvent event(PR_TRUE, NS_PAINT, this);
|
||||
event.region = boundsRect;
|
||||
status = DispatchEvent(&event);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
NS_ERROR("Invalid layer manager");
|
||||
}
|
||||
|
||||
// We had no covering child, so make sure we draw all the children,
|
||||
// starting from index 0.
|
||||
coveringChildIndex = 0;
|
||||
}
|
||||
|
||||
gfxPoint offset;
|
||||
|
||||
if (targetSurface)
|
||||
offset = targetSurface->GetDeviceOffset();
|
||||
|
||||
for (PRUint32 i = coveringChildIndex; i < mChildren.Length(); ++i) {
|
||||
if (mChildren[i]->mBounds.IsEmpty() ||
|
||||
!mChildren[i]->mBounds.Intersects(boundsRect))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (targetSurface)
|
||||
targetSurface->SetDeviceOffset(offset + gfxPoint(mChildren[i]->mBounds.x,
|
||||
mChildren[i]->mBounds.y));
|
||||
if (!mChildren[i]->DrawTo(targetSurface)) {
|
||||
|
||||
PRBool ok = mChildren[i]->DrawTo(targetSurface);
|
||||
|
||||
if (!ok) {
|
||||
ALOG("nsWindow[%p]::DrawTo child %d[%p] returned FALSE!", (void*) this, i, (void*)mChildren[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (targetSurface)
|
||||
targetSurface->SetDeviceOffset(offset);
|
||||
|
||||
return PR_TRUE;
|
||||
@ -753,7 +801,11 @@ nsWindow::OnDraw(AndroidGeckoEvent *ae)
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<gfxImageSurface> targetSurface;
|
||||
if (GetLayerManager()->GetBackendType() == LayerManager::LAYERS_BASIC) {
|
||||
drawType = AndroidGeckoSurfaceView::DRAW_SOFTWARE;
|
||||
} else {
|
||||
drawType = AndroidGeckoSurfaceView::DRAW_GLES_2;
|
||||
}
|
||||
|
||||
if (drawType == AndroidGeckoSurfaceView::DRAW_SOFTWARE) {
|
||||
int bufCap;
|
||||
@ -763,7 +815,8 @@ nsWindow::OnDraw(AndroidGeckoEvent *ae)
|
||||
sview.EndDrawing();
|
||||
return;
|
||||
}
|
||||
targetSurface =
|
||||
|
||||
nsRefPtr<gfxImageSurface> targetSurface =
|
||||
new gfxImageSurface(buf,
|
||||
gfxIntSize(mBounds.width, mBounds.height),
|
||||
mBounds.width * 4,
|
||||
@ -777,319 +830,17 @@ nsWindow::OnDraw(AndroidGeckoEvent *ae)
|
||||
while (ibuf < ibufMax) {
|
||||
*ibuf++ = (*ibuf & 0xff00ff00) | ((*ibuf & 0x00ff0000) >> 16) | ((*ibuf & 0x000000ff) << 16);
|
||||
}
|
||||
} else if (drawType == AndroidGeckoSurfaceView::DRAW_GLES_2) {
|
||||
NS_ASSERTION(sGLContext, "Drawing with GLES without a GL context?");
|
||||
|
||||
sview.EndDrawing();
|
||||
return;
|
||||
sGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
DrawTo(nsnull);
|
||||
|
||||
if (sGLContext)
|
||||
sGLContext->SwapBuffers();
|
||||
}
|
||||
|
||||
targetSurface =
|
||||
new gfxImageSurface(gfxIntSize(mBounds.width, mBounds.height), gfxASurface::ImageFormatARGB32);
|
||||
|
||||
if (!DrawTo(targetSurface)) {
|
||||
sview.EndDrawing();
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef USE_GLES2
|
||||
if (drawType != AndroidGeckoSurfaceView::DRAW_GLES_2) {
|
||||
ALOG("#### GL drawing path, but beingDrawing wanted something else!");
|
||||
sview.EndDrawing();
|
||||
return;
|
||||
}
|
||||
|
||||
static bool hasBGRA = false;
|
||||
|
||||
if (firstDraw) {
|
||||
const char *ext = (const char *) glGetString(GL_EXTENSIONS);
|
||||
ALOG("GL extensions: %s", ext);
|
||||
if (strstr(ext, "GL_EXT_bgra") ||
|
||||
strstr(ext, "GL_IMG_texture_format_BGRA8888") ||
|
||||
strstr(ext, "GL_EXT_texture_format_BGRA8888"))
|
||||
hasBGRA = true;
|
||||
|
||||
firstDraw = false;
|
||||
}
|
||||
|
||||
static GLuint textureId = GLuint(-1);
|
||||
static GLuint programId = GLuint(-1);
|
||||
static GLint positionLoc, texCoordLoc, textureLoc;
|
||||
if (textureId == GLuint(-1) || !glIsTexture(textureId)) {
|
||||
glGenTextures(1, &textureId);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, textureId);
|
||||
|
||||
/* Set required NPOT texture params, for baseline ES2 NPOT support */
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
const char *vsString =
|
||||
"attribute vec3 aPosition; \n"
|
||||
"attribute vec2 aTexCoord; \n"
|
||||
"varying vec2 vTexCoord; \n"
|
||||
"void main() { \n"
|
||||
" gl_Position = vec4(aPosition, 1.0); \n"
|
||||
" vTexCoord = aTexCoord; \n"
|
||||
"}";
|
||||
|
||||
/* Note that while the swizzle is, afaik, "free", the texture upload
|
||||
* can potentially be faster if the native hardware format is BGRA. So
|
||||
* we use BGRA if it's available.
|
||||
*/
|
||||
|
||||
const char *fsStringNoBGRA =
|
||||
"precision mediump float; \n"
|
||||
"varying vec2 vTexCoord; \n"
|
||||
"uniform sampler2D sTexture; \n"
|
||||
"void main() { \n"
|
||||
" gl_FragColor = vec4(texture2D(sTexture, vTexCoord).bgr, 1.0); \n"
|
||||
"}";
|
||||
|
||||
const char *fsStringBGRA =
|
||||
"precision mediump float; \n"
|
||||
"varying vec2 vTexCoord; \n"
|
||||
"uniform sampler2D sTexture; \n"
|
||||
"void main() { \n"
|
||||
" gl_FragColor = vec4(texture2D(sTexture, vTexCoord).rgb, 1.0); \n"
|
||||
"}";
|
||||
|
||||
GLint status;
|
||||
|
||||
GLuint vsh = glCreateShader(GL_VERTEX_SHADER);
|
||||
glShaderSource(vsh, 1, &vsString, NULL);
|
||||
glCompileShader(vsh);
|
||||
glGetShaderiv(vsh, GL_COMPILE_STATUS, &status);
|
||||
if (!status) {
|
||||
ALOG("Failed to compile vertex shader");
|
||||
return;
|
||||
}
|
||||
|
||||
GLuint fsh = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
glShaderSource(fsh, 1, hasBGRA ? &fsStringBGRA : &fsStringNoBGRA, NULL);
|
||||
glCompileShader(fsh);
|
||||
glGetShaderiv(fsh, GL_COMPILE_STATUS, &status);
|
||||
if (!status) {
|
||||
ALOG("Failed to compile fragment shader");
|
||||
return;
|
||||
}
|
||||
|
||||
programId = glCreateProgram();
|
||||
glAttachShader(programId, vsh);
|
||||
glAttachShader(programId, fsh);
|
||||
|
||||
glLinkProgram(programId);
|
||||
glGetProgramiv(programId, GL_LINK_STATUS, &status);
|
||||
if (!status) {
|
||||
ALOG("Failed to link program");
|
||||
return;
|
||||
}
|
||||
|
||||
positionLoc = glGetAttribLocation(programId, "aPosition");
|
||||
texCoordLoc = glGetAttribLocation(programId, "aTexCoord");
|
||||
textureLoc = glGetUniformLocation(programId, "sTexture");
|
||||
}
|
||||
|
||||
int texDimWidth = targetSurface->Width();
|
||||
int texDimHeight = targetSurface->Height();
|
||||
|
||||
glClearColor(1.0f, 0.3f, 0.3f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
glFrontFace(GL_CCW);
|
||||
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, textureId);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D,
|
||||
0,
|
||||
hasBGRA ? GL_BGRA_EXT : GL_RGBA,
|
||||
texDimWidth,
|
||||
texDimHeight,
|
||||
0,
|
||||
hasBGRA ? GL_BGRA_EXT : GL_RGBA,
|
||||
GL_UNSIGNED_BYTE,
|
||||
targetSurface->Data());
|
||||
|
||||
GLfloat texCoords[] = { 0.0f, 1.0f,
|
||||
0.0f, 0.0f,
|
||||
1.0f, 1.0f,
|
||||
1.0f, 0.0f };
|
||||
|
||||
GLfloat vCoords[] = { -1.0f, -1.0f, 0.0f,
|
||||
-1.0f, 1.0f, 0.0f,
|
||||
1.0f, -1.0f, 0.0f,
|
||||
1.0f, 1.0f, 0.0f };
|
||||
|
||||
glUseProgram(programId);
|
||||
|
||||
glVertexAttribPointer(positionLoc, 3, GL_FLOAT, GL_FALSE, 0, vCoords);
|
||||
glVertexAttribPointer(texCoordLoc, 2, GL_FLOAT, GL_FALSE, 0, texCoords);
|
||||
|
||||
glEnableVertexAttribArray(positionLoc);
|
||||
glEnableVertexAttribArray(texCoordLoc);
|
||||
|
||||
glUniform1i(textureLoc, 0);
|
||||
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
int err = glGetError();
|
||||
if (err)
|
||||
ALOG("GL error: %d", err);
|
||||
#else
|
||||
|
||||
/* GLES 1.0[1?] code.
|
||||
*
|
||||
* Two things:
|
||||
* NPOT textures are not supported by default, unlike with GLES 2
|
||||
* BGRA texture support is generally available, and might have
|
||||
* one of three different extension names.
|
||||
*/
|
||||
|
||||
static bool hasBGRA = false;
|
||||
static bool hasNPOT = false;
|
||||
static bool hasDrawTex = false;
|
||||
|
||||
if (firstDraw) {
|
||||
const char *ext = (const char *) glGetString(GL_EXTENSIONS);
|
||||
ALOG("GL extensions: %s", ext);
|
||||
if (strstr(ext, "GL_EXT_bgra") ||
|
||||
strstr(ext, "GL_IMG_texture_format_BGRA8888") ||
|
||||
strstr(ext, "GL_EXT_texture_format_BGRA8888"))
|
||||
hasBGRA = true;
|
||||
|
||||
if (strstr(ext, "GL_ARB_texture_non_power_of_two"))
|
||||
hasNPOT = true;
|
||||
|
||||
if (strstr(ext, "GL_OES_draw_texture"))
|
||||
hasDrawTex = true;
|
||||
|
||||
if (!hasBGRA)
|
||||
ALOG("No BGRA extension found -- colors will be weird! XXX FIXME");
|
||||
|
||||
firstDraw = false;
|
||||
}
|
||||
|
||||
glClearColor(1.0f, 0.3f, 0.3f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
// This is all the way a hack and will need to be changed with
|
||||
// real code to handle lost/reset context issues (e.g. when
|
||||
// rotating.
|
||||
static int lastTexDimWidth = -1;
|
||||
static int lastTexDimHeight = -1;
|
||||
static GLuint textureId = GLuint(-1);
|
||||
if (textureId == GLuint(-1) || !glIsTexture(textureId)) {
|
||||
glGenTextures(1, &textureId);
|
||||
|
||||
// Reset these to ensure that the non-NPOT path
|
||||
// calls TexImage2D first.
|
||||
lastTexDimWidth = -1;
|
||||
lastTexDimHeight = -1;
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, textureId);
|
||||
|
||||
int texDimWidth = targetSurface->Width();
|
||||
int texDimHeight = targetSurface->Height();
|
||||
|
||||
// Not sure if it would be faster to just call TexImage2D
|
||||
// if we have NPOT textures -- I'd hope that the driver
|
||||
// can turn that SubImage2D to an equivalent operation,
|
||||
// given that the dimensions are going to cover the full
|
||||
// size of the texture.
|
||||
|
||||
|
||||
// There seems to be a Tegra bug here, where we can't
|
||||
// do TexSubImage2D with GL_BGRA_EXT. We have NPOT there,
|
||||
// but it means that we have to have a separate codepath
|
||||
// for when we have NPOT to avoid the update with SubImage2D.
|
||||
|
||||
if (hasNPOT) {
|
||||
glTexImage2D(GL_TEXTURE_2D,
|
||||
0,
|
||||
hasBGRA ? GL_BGRA_EXT : GL_RGBA,
|
||||
texDimWidth,
|
||||
texDimHeight,
|
||||
0,
|
||||
hasBGRA ? GL_BGRA_EXT : GL_RGBA,
|
||||
GL_UNSIGNED_BYTE,
|
||||
targetSurface->Data());
|
||||
} else {
|
||||
texDimWidth = next_power_of_two(targetSurface->Width());
|
||||
texDimHeight = next_power_of_two(targetSurface->Height());
|
||||
|
||||
if (lastTexDimWidth != texDimWidth ||
|
||||
lastTexDimHeight != texDimHeight)
|
||||
{
|
||||
// Set the texture size, but don't load
|
||||
// data.
|
||||
glTexImage2D(GL_TEXTURE_2D,
|
||||
0,
|
||||
hasBGRA ? GL_BGRA_EXT : GL_RGBA,
|
||||
texDimWidth,
|
||||
texDimHeight,
|
||||
0,
|
||||
hasBGRA ? GL_BGRA_EXT : GL_RGBA,
|
||||
GL_UNSIGNED_BYTE,
|
||||
NULL);
|
||||
|
||||
lastTexDimWidth = texDimWidth;
|
||||
lastTexDimHeight = texDimHeight;
|
||||
}
|
||||
|
||||
// then actually load the data in the sub-rectangle
|
||||
glTexSubImage2D(GL_TEXTURE_2D,
|
||||
0,
|
||||
0, 0,
|
||||
targetSurface->Width(),
|
||||
targetSurface->Height(),
|
||||
hasBGRA ? GL_BGRA_EXT : GL_RGBA,
|
||||
GL_UNSIGNED_BYTE,
|
||||
targetSurface->Data());
|
||||
}
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
glFrontFace(GL_CCW);
|
||||
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_ALPHA_TEST);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
GLfloat texCoordW = GLfloat(targetSurface->Width()) / GLfloat(texDimWidth);
|
||||
GLfloat texCoordH = GLfloat(targetSurface->Height()) / GLfloat(texDimHeight);
|
||||
|
||||
GLfloat texCoords[] = { 0.0f, texCoordH,
|
||||
0.0f, 0.0f,
|
||||
texCoordW, texCoordH,
|
||||
texCoordW, 0.0f };
|
||||
|
||||
GLfloat vCoords[] = { -1.0f, -1.0f, 0.0f,
|
||||
-1.0f, 1.0f, 0.0f,
|
||||
1.0f, -1.0f, 0.0f,
|
||||
1.0f, 1.0f, 0.0f };
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
|
||||
glVertexPointer(3, GL_FLOAT, 0, vCoords);
|
||||
glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
|
||||
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
#endif
|
||||
|
||||
sview.EndDrawing();
|
||||
}
|
||||
|
||||
@ -1149,6 +900,10 @@ void *
|
||||
nsWindow::GetNativeData(PRUint32 aDataType)
|
||||
{
|
||||
switch (aDataType) {
|
||||
// used by GLContextProviderEGL, NULL is EGL_DEFAULT_DISPLAY
|
||||
case NS_NATIVE_DISPLAY:
|
||||
return NULL;
|
||||
|
||||
case NS_NATIVE_WIDGET:
|
||||
return (void *) this;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user