diff --git a/mobile/android/base/Makefile.in b/mobile/android/base/Makefile.in index 16e4a0338b4a..c827a807899c 100644 --- a/mobile/android/base/Makefile.in +++ b/mobile/android/base/Makefile.in @@ -123,6 +123,7 @@ FENNEC_JAVA_FILES = \ gfx/CheckerboardImage.java \ gfx/DisplayPortCalculator.java \ gfx/DisplayPortMetrics.java \ + gfx/FlexibleGLSurfaceView.java \ gfx/FloatSize.java \ gfx/GeckoLayerClient.java \ gfx/GLController.java \ diff --git a/mobile/android/base/gfx/FlexibleGLSurfaceView.java b/mobile/android/base/gfx/FlexibleGLSurfaceView.java new file mode 100644 index 000000000000..f4499e50e420 --- /dev/null +++ b/mobile/android/base/gfx/FlexibleGLSurfaceView.java @@ -0,0 +1,158 @@ +/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Android code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011-2012 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Patrick Walton + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +package org.mozilla.gecko.gfx; + +import org.mozilla.gecko.GeckoApp; +import android.content.Context; +import android.graphics.PixelFormat; +import android.opengl.GLSurfaceView; +import android.util.AttributeSet; +import android.util.Log; +import android.view.SurfaceHolder; +import android.view.SurfaceView; +import javax.microedition.khronos.opengles.GL10; + +/* + * This class extends SurfaceView and allows dynamically switching between two modes + * of operation. In one mode, it is used like a GLSurfaceView, and has it's own GL + * thread. In the other mode, it allows external code to perform GL composition, by + * exposing the GL controller. + * + * In our case, we start off in the first mode because we are rendering the placeholder + * image. This mode is initiated by a call to createGLThread(). Once Gecko comes up, + * it invokes registerCxxCompositor() via a JNI call, which shuts down the GL thread and + * returns the GL controller. The JNI code then takes the EGL surface from the GL + * controller and allows the off-main thread compositor to deal with it directly. + */ +public class FlexibleGLSurfaceView extends SurfaceView implements SurfaceHolder.Callback { + private static final String LOGTAG = "GeckoFlexibleGLSurfaceView"; + + private GLSurfaceView.Renderer mRenderer; + private GLController mController; + private Listener mListener; + + public FlexibleGLSurfaceView(Context context) { + super(context); + init(); + } + + public FlexibleGLSurfaceView(Context context, AttributeSet attributeSet) { + super(context, attributeSet); + init(); + } + + public void init() { + SurfaceHolder holder = getHolder(); + holder.addCallback(this); + holder.setFormat(PixelFormat.RGB_565); + + mController = new GLController(this); + } + + public void setRenderer(GLSurfaceView.Renderer renderer) { + mRenderer = renderer; + } + + public GLSurfaceView.Renderer getRenderer() { + return mRenderer; + } + + public void setListener(Listener listener) { + mListener = listener; + } + + public synchronized void requestRender() { + if (mListener != null) { + mListener.renderRequested(); + } + } + + public synchronized GLController getGLController() { + return mController; + } + + /** Implementation of SurfaceHolder.Callback */ + public synchronized void surfaceChanged(SurfaceHolder holder, int format, int width, + int height) { + mController.sizeChanged(width, height); + + if (mListener != null) { + mListener.surfaceChanged(width, height); + } + } + + /** Implementation of SurfaceHolder.Callback */ + public synchronized void surfaceCreated(SurfaceHolder holder) { + mController.surfaceCreated(); + } + + /** Implementation of SurfaceHolder.Callback */ + public synchronized void surfaceDestroyed(SurfaceHolder holder) { + mController.surfaceDestroyed(); + if (mListener != null) { + mListener.compositionPauseRequested(); + } + } + + /** This function is invoked by Gecko (compositor thread) via JNI; be careful when modifying signature. */ + public static GLController registerCxxCompositor() { + try { + FlexibleGLSurfaceView flexView = (FlexibleGLSurfaceView)GeckoApp.mAppContext.getLayerController().getView(); + return flexView.getGLController(); + } catch (Exception e) { + Log.e(LOGTAG, "### Exception! " + e); + return null; + } + } + + public interface Listener { + void renderRequested(); + void compositionPauseRequested(); + void compositionResumeRequested(); + void surfaceChanged(int width, int height); + } + + public static class FlexibleGLSurfaceViewException extends RuntimeException { + public static final long serialVersionUID = 1L; + + FlexibleGLSurfaceViewException(String e) { + super(e); + } + } +} + diff --git a/mobile/android/base/gfx/GLController.java b/mobile/android/base/gfx/GLController.java index 04c544ef8e9e..26afdd8839d6 100644 --- a/mobile/android/base/gfx/GLController.java +++ b/mobile/android/base/gfx/GLController.java @@ -53,7 +53,7 @@ public class GLController { private static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098; private static final String LOGTAG = "GeckoGLController"; - private LayerView mView; + private FlexibleGLSurfaceView mView; private int mGLVersion; private boolean mSurfaceValid; private int mWidth, mHeight; @@ -77,7 +77,7 @@ public class GLController { EGL10.EGL_NONE }; - public GLController(LayerView view) { + public GLController(FlexibleGLSurfaceView view) { mView = view; mGLVersion = 2; mSurfaceValid = false; @@ -92,7 +92,7 @@ public class GLController { public EGLConfig getEGLConfig() { return mEGLConfig; } public EGLContext getEGLContext() { return mEGLContext; } public EGLSurface getEGLSurface() { return mEGLSurface; } - public LayerView getView() { return mView; } + public FlexibleGLSurfaceView getView() { return mView; } public boolean hasSurface() { return mEGLSurface != null; diff --git a/mobile/android/base/gfx/GeckoLayerClient.java b/mobile/android/base/gfx/GeckoLayerClient.java index 9eba993dbf16..ecda6c07c70b 100644 --- a/mobile/android/base/gfx/GeckoLayerClient.java +++ b/mobile/android/base/gfx/GeckoLayerClient.java @@ -58,7 +58,7 @@ import android.util.Log; import android.view.View; public class GeckoLayerClient implements GeckoEventResponder, - LayerView.Listener { + FlexibleGLSurfaceView.Listener { private static final String LOGTAG = "GeckoLayerClient"; private static final String PREF_DISPLAYPORT_STRATEGY = "gfx.displayport.strategy"; @@ -407,19 +407,19 @@ public class GeckoLayerClient implements GeckoEventResponder, mLayerRenderer.deactivateDefaultProgram(); } - /** Implementation of LayerView.Listener */ + /** Implementation of FlexibleGLSurfaceView.Listener */ public void renderRequested() { GeckoAppShell.scheduleComposite(); } - /** Implementation of LayerView.Listener */ + /** Implementation of FlexibleGLSurfaceView.Listener */ public void compositionPauseRequested() { // We need to coordinate with Gecko when pausing composition, to ensure // that Gecko never executes a draw event while the compositor is paused. GeckoAppShell.sendEventToGecko(GeckoEvent.createCompositorPauseEvent()); } - /** Implementation of LayerView.Listener */ + /** Implementation of FlexibleGLSurfaceView.Listener */ public void compositionResumeRequested() { // Asking Gecko to resume the compositor takes too long (see // https://bugzilla.mozilla.org/show_bug.cgi?id=735230#c23), so we @@ -429,7 +429,7 @@ public class GeckoLayerClient implements GeckoEventResponder, GeckoAppShell.sendEventToGecko(GeckoEvent.createCompositorResumeEvent()); } - /** Implementation of LayerView.Listener */ + /** Implementation of FlexibleGLSurfaceView.Listener */ public void surfaceChanged(int width, int height) { mLayerController.setViewportSize(new FloatSize(width, height)); diff --git a/mobile/android/base/gfx/LayerView.java b/mobile/android/base/gfx/LayerView.java index b22ce9b2a87a..6174dda36578 100644 --- a/mobile/android/base/gfx/LayerView.java +++ b/mobile/android/base/gfx/LayerView.java @@ -58,16 +58,6 @@ import android.util.Log; import java.nio.IntBuffer; import java.util.LinkedList; -import org.mozilla.gecko.GeckoApp; -import android.content.Context; -import android.graphics.PixelFormat; -import android.opengl.GLSurfaceView; -import android.util.AttributeSet; -import android.view.SurfaceHolder; -import android.view.SurfaceView; -import javax.microedition.khronos.opengles.GL10; - - /** * A view rendered by the layer compositor. * @@ -76,10 +66,9 @@ import javax.microedition.khronos.opengles.GL10; * * Note that LayerView is accessed by Robocop via reflection. */ -public class LayerView extends SurfaceView implements SurfaceHolder.Callback { +public class LayerView extends FlexibleGLSurfaceView { private Context mContext; private LayerController mController; - private GLController mGLController; private InputConnectionHandler mInputConnectionHandler; private LayerRenderer mRenderer; private GestureDetector mGestureDetector; @@ -92,8 +81,6 @@ public class LayerView extends SurfaceView implements SurfaceHolder.Callback { /* Must be a PAINT_xxx constant */ private int mPaintState = PAINT_NONE; - private Listener mListener; - /* Flags used to determine when to show the painted surface. The integer * order must correspond to the order in which these states occur. */ public static final int PAINT_NONE = 0; @@ -104,14 +91,10 @@ public class LayerView extends SurfaceView implements SurfaceHolder.Callback { public LayerView(Context context, LayerController controller) { super(context); - SurfaceHolder holder = getHolder(); - holder.addCallback(this); - holder.setFormat(PixelFormat.RGB_565); - - mGLController = new GLController(this); mContext = context; mController = controller; mRenderer = new LayerRenderer(this); + setRenderer(mRenderer); mGestureDetector = new GestureDetector(context, controller.getGestureListener()); mScaleGestureDetector = new SimpleScaleGestureDetector(controller.getScaleGestureListener()); @@ -213,9 +196,15 @@ public class LayerView extends SurfaceView implements SurfaceHolder.Callback { return false; } - public synchronized void requestRender() { - if (mListener != null) { - mListener.renderRequested(); + @Override + public void requestRender() { + super.requestRender(); + + synchronized(this) { + if (!mRenderTimeReset) { + mRenderTimeReset = true; + mRenderTime = System.nanoTime(); + } } } @@ -249,12 +238,13 @@ public class LayerView extends SurfaceView implements SurfaceHolder.Callback { public void setLayerRenderer(LayerRenderer renderer) { mRenderer = renderer; + setRenderer(mRenderer); } public LayerRenderer getLayerRenderer() { return mRenderer; } - + /* paintState must be a PAINT_xxx constant. The state will only be changed * if paintState represents a state that occurs after the current state. */ public void setPaintState(int paintState) { @@ -267,61 +257,5 @@ public class LayerView extends SurfaceView implements SurfaceHolder.Callback { public int getPaintState() { return mPaintState; } - - - public GLSurfaceView.Renderer getRenderer() { - return mRenderer; - } - - public void setListener(Listener listener) { - mListener = listener; - } - - public synchronized GLController getGLController() { - return mGLController; - } - - /** Implementation of SurfaceHolder.Callback */ - public synchronized void surfaceChanged(SurfaceHolder holder, int format, int width, - int height) { - mGLController.sizeChanged(width, height); - - if (mListener != null) { - mListener.surfaceChanged(width, height); - } - } - - /** Implementation of SurfaceHolder.Callback */ - public synchronized void surfaceCreated(SurfaceHolder holder) { - mGLController.surfaceCreated(); - } - - /** Implementation of SurfaceHolder.Callback */ - public synchronized void surfaceDestroyed(SurfaceHolder holder) { - mGLController.surfaceDestroyed(); - - if (mListener != null) { - mListener.compositionPauseRequested(); - } - } - - /** This function is invoked by Gecko (compositor thread) via JNI; be careful when modifying signature. */ - public static GLController registerCxxCompositor() { - try { - LayerView layerView = GeckoApp.mAppContext.getLayerController().getView(); - return layerView.getGLController(); - } catch (Exception e) { - Log.e(LOGTAG, "### Exception! " + e); - return null; - } - } - - public interface Listener { - void renderRequested(); - void compositionPauseRequested(); - void compositionResumeRequested(); - void surfaceChanged(int width, int height); - } - - } + diff --git a/widget/android/AndroidBridge.cpp b/widget/android/AndroidBridge.cpp index 8ca5e573a263..cda316c62b04 100644 --- a/widget/android/AndroidBridge.cpp +++ b/widget/android/AndroidBridge.cpp @@ -201,7 +201,7 @@ AndroidBridge::Init(JNIEnv *jEnv, jStringClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("java/lang/String")); #ifdef MOZ_JAVA_COMPOSITOR - jLayerView = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("org/mozilla/gecko/gfx/LayerView")); + jFlexSurfaceView = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("org/mozilla/gecko/gfx/FlexibleGLSurfaceView")); AndroidGLController::Init(jEnv); AndroidEGLObject::Init(jEnv); @@ -1119,9 +1119,9 @@ AndroidBridge::RegisterCompositor() AutoLocalJNIFrame jniFrame(env, 3); - jmethodID registerCompositor = env->GetStaticMethodID(jLayerView, "registerCxxCompositor", "()Lorg/mozilla/gecko/gfx/GLController;"); + jmethodID registerCompositor = env->GetStaticMethodID(jFlexSurfaceView, "registerCxxCompositor", "()Lorg/mozilla/gecko/gfx/GLController;"); - jobject glController = env->CallStaticObjectMethod(jLayerView, registerCompositor); + jobject glController = env->CallStaticObjectMethod(jFlexSurfaceView, registerCompositor); sController.Acquire(env, glController); sController.SetGLVersion(2); diff --git a/widget/android/AndroidBridge.h b/widget/android/AndroidBridge.h index 7e2c5cf1f8d9..9b6fcca7bb8e 100644 --- a/widget/android/AndroidBridge.h +++ b/widget/android/AndroidBridge.h @@ -49,7 +49,7 @@ #include "nsIObserver.h" #include "nsThreadUtils.h" -#include "AndroidLayerViewWrapper.h" +#include "AndroidFlexViewWrapper.h" #include "AndroidJavaWrappers.h" #include "nsIMutableArray.h" @@ -554,7 +554,7 @@ protected: jclass jEGLContextClass; jclass jEGL10Class; - jclass jLayerView; + jclass jFlexSurfaceView; jmethodID jRegisterCompositorMethod; // some convinient types to have around diff --git a/widget/android/AndroidLayerViewWrapper.cpp b/widget/android/AndroidFlexViewWrapper.cpp similarity index 93% rename from widget/android/AndroidLayerViewWrapper.cpp rename to widget/android/AndroidFlexViewWrapper.cpp index 710d9272d774..1e95c91144fb 100644 --- a/widget/android/AndroidLayerViewWrapper.cpp +++ b/widget/android/AndroidFlexViewWrapper.cpp @@ -35,11 +35,11 @@ * * ***** END LICENSE BLOCK ***** */ -#include "AndroidLayerViewWrapper.h" +#include "AndroidFlexViewWrapper.h" #include "nsDebug.h" #define ASSERT_THREAD() \ - NS_ASSERTION(pthread_self() == mThread, "Something is calling AndroidGLController from the wrong thread!") + NS_ASSERTION((void*)pthread_self() == mThread, "Something is calling AndroidGLController from the wrong thread!") static jfieldID jEGLSurfacePointerField = 0; @@ -55,7 +55,7 @@ jmethodID AndroidGLController::jWaitForValidSurfaceMethod = 0; jmethodID AndroidGLController::jProvideEGLSurfaceMethod = 0; void -AndroidGLController::Init(JNIEnv* aJEnv) +AndroidGLController::Init(JNIEnv *aJEnv) { jclass jClass = reinterpret_cast(aJEnv->NewGlobalRef(aJEnv->FindClass("org/mozilla/gecko/gfx/GLController"))); @@ -69,7 +69,7 @@ void AndroidGLController::Acquire(JNIEnv* aJEnv, jobject aJObj) { mJEnv = aJEnv; - mThread = pthread_self(); + mThread = (void*)pthread_self(); mJObj = aJEnv->NewGlobalRef(aJObj); } diff --git a/widget/android/AndroidLayerViewWrapper.h b/widget/android/AndroidFlexViewWrapper.h similarity index 90% rename from widget/android/AndroidLayerViewWrapper.h rename to widget/android/AndroidFlexViewWrapper.h index eac242544124..e3c88c8a9498 100644 --- a/widget/android/AndroidLayerViewWrapper.h +++ b/widget/android/AndroidFlexViewWrapper.h @@ -35,24 +35,27 @@ * * ***** END LICENSE BLOCK ***** */ -#ifndef AndroidLayerViewWrapper_h__ -#define AndroidLayerViewWrapper_h__ +#ifndef AndroidFlexViewWrapper_h__ +#define AndroidFlexViewWrapper_h__ #include +#include +#include #include +#include class AndroidEGLObject { public: static void Init(JNIEnv* aJEnv); }; -typedef void* EGLSurface; +typedef void *EGLSurface; class AndroidGLController { public: static void Init(JNIEnv* aJEnv); - void Acquire(JNIEnv* aJEnv, jobject aJObj); + void Acquire(JNIEnv *aJEnv, jobject aJObj); void SetGLVersion(int aVersion); EGLSurface ProvideEGLSurface(); void WaitForValidSurface(); @@ -63,8 +66,8 @@ private: static jmethodID jProvideEGLSurfaceMethod; // the JNIEnv for the compositor thread - JNIEnv* mJEnv; - pthread_t mThread; + JNIEnv *mJEnv; + void *mThread; jobject mJObj; }; diff --git a/widget/android/Makefile.in b/widget/android/Makefile.in index b2270fc91fc7..32d8c4c4c7a0 100644 --- a/widget/android/Makefile.in +++ b/widget/android/Makefile.in @@ -62,7 +62,7 @@ CPPSRCS = \ AndroidJavaWrappers.cpp \ AndroidBridge.cpp \ AndroidDirectTexture.cpp \ - AndroidLayerViewWrapper.cpp \ + AndroidFlexViewWrapper.cpp \ AndroidGraphicBuffer.cpp \ AndroidJNI.cpp \ AndroidMediaLayer.cpp \ @@ -92,7 +92,7 @@ XPIDLSRCS = \ SHARED_LIBRARY_LIBS = ../xpwidgets/libxpwidgets_s.a -EXPORTS = AndroidBridge.h AndroidJavaWrappers.h AndroidLayerViewWrapper.h +EXPORTS = AndroidBridge.h AndroidJavaWrappers.h AndroidFlexViewWrapper.h include $(topsrcdir)/config/rules.mk