mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-30 08:12:05 +00:00
Bug 844275 - Drive the layer manager creation from the GLController rather than GetLayerManager. r=Cwiiis
This commit is contained in:
parent
a6d771029a
commit
f86cafabb9
@ -551,7 +551,7 @@ public:
|
||||
EGL_NO_CONTEXT);
|
||||
if (!mSurface) {
|
||||
#ifdef MOZ_ANDROID_OMTC
|
||||
mSurface = mozilla::AndroidBridge::Bridge()->ProvideEGLSurface(false);
|
||||
mSurface = mozilla::AndroidBridge::Bridge()->ProvideEGLSurface();
|
||||
if (!mSurface) {
|
||||
return false;
|
||||
}
|
||||
@ -2077,7 +2077,7 @@ GLContextProviderEGL::CreateForWindow(nsIWidget *aWidget)
|
||||
|
||||
#ifdef MOZ_ANDROID_OMTC
|
||||
mozilla::AndroidBridge::Bridge()->RegisterCompositor();
|
||||
EGLSurface surface = mozilla::AndroidBridge::Bridge()->ProvideEGLSurface(true);
|
||||
EGLSurface surface = mozilla::AndroidBridge::Bridge()->ProvideEGLSurface();
|
||||
#else
|
||||
EGLSurface surface = CreateSurfaceForWindow(aWidget, config);
|
||||
#endif
|
||||
|
@ -5,8 +5,12 @@
|
||||
|
||||
package org.mozilla.gecko.gfx;
|
||||
|
||||
import org.mozilla.gecko.GeckoApp;
|
||||
import org.mozilla.gecko.GeckoAppShell;
|
||||
import org.mozilla.gecko.GeckoEvent;
|
||||
import org.mozilla.gecko.GeckoThread;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import javax.microedition.khronos.egl.EGL10;
|
||||
import javax.microedition.khronos.egl.EGLConfig;
|
||||
@ -41,6 +45,7 @@ public class GLController {
|
||||
private EGL10 mEGL;
|
||||
private EGLDisplay mEGLDisplay;
|
||||
private EGLConfig mEGLConfig;
|
||||
private EGLSurface mEGLSurface;
|
||||
|
||||
private static final int LOCAL_EGL_OPENGL_ES2_BIT = 4;
|
||||
|
||||
@ -64,22 +69,11 @@ public class GLController {
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
/* Wait until we are allowed to use EGL functions on the Surface backing
|
||||
* this window.
|
||||
* This function is invoked by JNI */
|
||||
synchronized void waitForValidSurface() {
|
||||
while (!mSurfaceValid) {
|
||||
try {
|
||||
wait();
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
synchronized void surfaceDestroyed() {
|
||||
GeckoApp.assertOnUiThread();
|
||||
|
||||
mSurfaceValid = false;
|
||||
notifyAll();
|
||||
mEGLSurface = null;
|
||||
|
||||
// We need to coordinate with Gecko when pausing composition, to ensure
|
||||
// that Gecko never executes a draw event while the compositor is paused.
|
||||
@ -95,13 +89,85 @@ public class GLController {
|
||||
}
|
||||
|
||||
synchronized void surfaceChanged(int newWidth, int newHeight) {
|
||||
GeckoApp.assertOnUiThread();
|
||||
|
||||
mWidth = newWidth;
|
||||
mHeight = newHeight;
|
||||
|
||||
if (mSurfaceValid) {
|
||||
// We need to make this call even when the compositor isn't currently
|
||||
// paused (e.g. during an orientation change), to make the compositor
|
||||
// aware of the changed surface.
|
||||
resumeCompositor(mWidth, mHeight);
|
||||
return;
|
||||
}
|
||||
mSurfaceValid = true;
|
||||
notifyAll();
|
||||
|
||||
// If we get here, we supposedly have a valid surface where previously we
|
||||
// did not. So we're going to create the window surface and hold on to it
|
||||
// until the compositor comes asking for it. However, we can't call
|
||||
// eglCreateWindowSurface right away because the UI thread isn't *actually*
|
||||
// done setting up - for some reason Android will send us a surfaceChanged
|
||||
// notification before the surface is actually ready. So, we need to do the
|
||||
// call to eglCreateWindowSurface in a runnable posted back to the UI thread
|
||||
// that will run once this call unwinds all the way out and Android finishes
|
||||
// doing its thing.
|
||||
|
||||
mView.post(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
// Re-check mSurfaceValid in case the surface was destroyed between
|
||||
// where we set it to true above and this runnable getting run.
|
||||
// If mSurfaceValid is still true, try to create mEGLSurface. If
|
||||
// mSurfaceValid is false, leave mEGLSurface as null. So at the end
|
||||
// of this block mEGLSurface will be null (or EGL_NO_SURFACE) if
|
||||
// eglCreateWindowSurface failed or if mSurfaceValid changed to false.
|
||||
if (mSurfaceValid) {
|
||||
if (mEGL == null) {
|
||||
initEGL();
|
||||
}
|
||||
|
||||
mEGLSurface = mEGL.eglCreateWindowSurface(mEGLDisplay, mEGLConfig, mView.getNativeWindow(), null);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(LOGTAG, "Unable to create window surface", e);
|
||||
}
|
||||
if (mEGLSurface == null || mEGLSurface == EGL10.EGL_NO_SURFACE) {
|
||||
mSurfaceValid = false;
|
||||
mEGLSurface = null; // normalize EGL_NO_SURFACE to null to simplify later checks
|
||||
Log.e(LOGTAG, "EGL window surface could not be created: " + getEGLError());
|
||||
return;
|
||||
}
|
||||
// At this point mSurfaceValid is true and mEGLSurface is a valid surface. Try
|
||||
// to create the compositor if it hasn't been created already.
|
||||
createCompositor();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void createCompositor() {
|
||||
GeckoApp.assertOnUiThread();
|
||||
|
||||
if (mCompositorCreated) {
|
||||
// If the compositor has already been created, just resume it instead. We don't need
|
||||
// to block here because if the surface is destroyed before the compositor grabs it,
|
||||
// we can handle that gracefully (i.e. the compositor will remain paused).
|
||||
resumeCompositor(mWidth, mHeight);
|
||||
return;
|
||||
}
|
||||
|
||||
// Only try to create the compositor if we have a valid surface and gecko is up. When these
|
||||
// two conditions are satisfied, we can be relatively sure that the compositor creation will
|
||||
// happen without needing to block anyhwere. Do it with a sync gecko event so that the
|
||||
// android doesn't have a chance to destroy our surface in between.
|
||||
if (mEGLSurface != null && GeckoThread.checkLaunchState(GeckoThread.LaunchState.GeckoRunning)) {
|
||||
GeckoAppShell.sendEventToGeckoSync(GeckoEvent.createCompositorResumeEvent());
|
||||
}
|
||||
}
|
||||
|
||||
void compositorCreated() {
|
||||
// This is invoked on the compositor thread, while the java UI thread
|
||||
// is blocked on the gecko sync event in createCompositor() above
|
||||
mCompositorCreated = true;
|
||||
}
|
||||
|
||||
@ -148,30 +214,9 @@ public class GLController {
|
||||
throw new GLControllerException("No suitable EGL configuration found");
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides an EGLSurface without assuming ownership of this surface.
|
||||
* This class does not keep a reference to the provided EGL surface; the
|
||||
* caller assumes ownership of the surface once it is returned.
|
||||
* This function is invoked by JNI */
|
||||
/* This function is invoked by JNI on the compositor thread */
|
||||
private EGLSurface provideEGLSurface() {
|
||||
synchronized (this) {
|
||||
if (!mSurfaceValid) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (mEGL == null) {
|
||||
initEGL();
|
||||
}
|
||||
|
||||
Object window = mView.getNativeWindow();
|
||||
EGLSurface surface = mEGL.eglCreateWindowSurface(mEGLDisplay, mEGLConfig, window, null);
|
||||
if (surface == null || surface == EGL10.EGL_NO_SURFACE) {
|
||||
throw new GLControllerException("EGL window surface could not be created! " +
|
||||
getEGLError());
|
||||
}
|
||||
|
||||
return surface;
|
||||
return mEGLSurface;
|
||||
}
|
||||
|
||||
private String getEGLError() {
|
||||
|
@ -126,6 +126,17 @@ public class GeckoLayerClient implements LayerView.Listener, PanZoomTarget
|
||||
sendResizeEventIfNecessary(true);
|
||||
|
||||
DisplayPortCalculator.initPrefs();
|
||||
|
||||
// Gecko being ready is one of the two conditions (along with having an available
|
||||
// surface) that cause us to create the compositor. So here, now that we know gecko
|
||||
// is ready, call createCompositor() to see if we can actually do the creation.
|
||||
// This needs to run on the UI thread so that the surface validity can't change on
|
||||
// us while we're in the middle of creating the compositor.
|
||||
mView.post(new Runnable() {
|
||||
public void run() {
|
||||
mView.getGLController().createCompositor();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
@ -604,11 +615,6 @@ public class GeckoLayerClient implements LayerView.Listener, PanZoomTarget
|
||||
@Override
|
||||
public void surfaceChanged(int width, int height) {
|
||||
setViewportSize(width, height);
|
||||
|
||||
// We need to make this call even when the compositor isn't currently
|
||||
// paused (e.g. during an orientation change), to make the compositor
|
||||
// aware of the changed surface.
|
||||
mView.getGLController().resumeCompositor(width, height);
|
||||
}
|
||||
|
||||
/** Implementation of PanZoomTarget */
|
||||
|
@ -1142,11 +1142,8 @@ AndroidBridge::RegisterCompositor(JNIEnv *env)
|
||||
}
|
||||
|
||||
EGLSurface
|
||||
AndroidBridge::ProvideEGLSurface(bool waitUntilValid)
|
||||
AndroidBridge::ProvideEGLSurface()
|
||||
{
|
||||
if (waitUntilValid) {
|
||||
sController.WaitForValidSurface();
|
||||
}
|
||||
return sController.ProvideEGLSurface();
|
||||
}
|
||||
|
||||
|
@ -256,7 +256,7 @@ public:
|
||||
|
||||
// Switch Java to composite with the Gecko Compositor thread
|
||||
void RegisterCompositor(JNIEnv* env = NULL);
|
||||
EGLSurface ProvideEGLSurface(bool waitUntilValid);
|
||||
EGLSurface ProvideEGLSurface();
|
||||
|
||||
bool GetStaticStringField(const char *classID, const char *field, nsAString &result, JNIEnv* env = nullptr);
|
||||
|
||||
|
@ -26,7 +26,6 @@ void AndroidEGLObject::Init(JNIEnv* aJEnv) {
|
||||
jEGLSurfacePointerField = aJEnv->GetFieldID(jClass, "mEGLSurface", "I");
|
||||
}
|
||||
|
||||
jmethodID AndroidGLController::jWaitForValidSurfaceMethod = 0;
|
||||
jmethodID AndroidGLController::jProvideEGLSurfaceMethod = 0;
|
||||
|
||||
void
|
||||
@ -36,7 +35,6 @@ AndroidGLController::Init(JNIEnv* aJEnv)
|
||||
|
||||
jProvideEGLSurfaceMethod = aJEnv->GetMethodID(jClass, "provideEGLSurface",
|
||||
"()Ljavax/microedition/khronos/egl/EGLSurface;");
|
||||
jWaitForValidSurfaceMethod = aJEnv->GetMethodID(jClass, "waitForValidSurface", "()V");
|
||||
}
|
||||
|
||||
void
|
||||
@ -62,11 +60,3 @@ AndroidGLController::ProvideEGLSurface()
|
||||
|
||||
return reinterpret_cast<EGLSurface>(mJEnv->GetIntField(jObj, jEGLSurfacePointerField));
|
||||
}
|
||||
|
||||
void
|
||||
AndroidGLController::WaitForValidSurface()
|
||||
{
|
||||
ASSERT_THREAD();
|
||||
AutoLocalJNIFrame jniFrame(mJEnv, 0);
|
||||
mJEnv->CallVoidMethod(mJObj, jWaitForValidSurfaceMethod);
|
||||
}
|
||||
|
@ -22,10 +22,8 @@ public:
|
||||
|
||||
void Acquire(JNIEnv* aJEnv, jobject aJObj);
|
||||
EGLSurface ProvideEGLSurface();
|
||||
void WaitForValidSurface();
|
||||
|
||||
private:
|
||||
static jmethodID jWaitForValidSurfaceMethod;
|
||||
static jmethodID jProvideEGLSurfaceMethod;
|
||||
|
||||
// the JNIEnv for the compositor thread
|
||||
|
@ -688,41 +688,49 @@ nsWindow::GetLayerManager(PLayersChild*, LayersBackend, LayerManagerPersistence,
|
||||
if (mLayerManager) {
|
||||
return mLayerManager;
|
||||
}
|
||||
// for OMTC allow use of the single layer manager/compositor
|
||||
// shared across all windows
|
||||
if (UseOffMainThreadCompositing()) {
|
||||
return sLayerManager;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
nsWindow::CreateLayerManager()
|
||||
{
|
||||
if (mLayerManager) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsWindow *topLevelWindow = FindTopLevel();
|
||||
if (!topLevelWindow || topLevelWindow->mWindowType == eWindowType_invisible) {
|
||||
// don't create a layer manager for an invisible top-level window
|
||||
return nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
mUseLayersAcceleration = ComputeShouldAccelerate(mUseLayersAcceleration);
|
||||
|
||||
bool useCompositor = UseOffMainThreadCompositing();
|
||||
|
||||
if (useCompositor) {
|
||||
if (UseOffMainThreadCompositing()) {
|
||||
if (sLayerManager) {
|
||||
return sLayerManager;
|
||||
return;
|
||||
}
|
||||
CreateCompositor();
|
||||
if (mLayerManager) {
|
||||
// for OMTC create a single layer manager and compositor that will be
|
||||
// used for all windows.
|
||||
SetCompositor(mLayerManager, mCompositorParent, mCompositorChild);
|
||||
return mLayerManager;
|
||||
return;
|
||||
}
|
||||
|
||||
// If we get here, then off main thread compositing failed to initialize.
|
||||
sFailedToCreateGLContext = true;
|
||||
}
|
||||
|
||||
if (!mUseLayersAcceleration ||
|
||||
sFailedToCreateGLContext)
|
||||
{
|
||||
if (!mUseLayersAcceleration || sFailedToCreateGLContext) {
|
||||
printf_stderr(" -- creating basic, not accelerated\n");
|
||||
mLayerManager = CreateBasicLayerManager();
|
||||
}
|
||||
|
||||
return mLayerManager;
|
||||
}
|
||||
|
||||
void
|
||||
@ -886,6 +894,8 @@ nsWindow::OnGlobalAndroidEvent(AndroidGeckoEvent *ae)
|
||||
break;
|
||||
|
||||
case AndroidGeckoEvent::COMPOSITOR_RESUME:
|
||||
win->CreateLayerManager();
|
||||
|
||||
// When we receive this, the compositor has already been told to
|
||||
// resume. (It turns out that waiting till we reach here to tell
|
||||
// the compositor to resume takes too long, resulting in a black
|
||||
@ -2231,7 +2241,7 @@ nsWindow::DrawWindowOverlay(LayerManager* aManager, nsIntRect aRect)
|
||||
nsRefPtr<mozilla::layers::LayerManager> nsWindow::sLayerManager = 0;
|
||||
nsRefPtr<mozilla::layers::CompositorParent> nsWindow::sCompositorParent = 0;
|
||||
nsRefPtr<mozilla::layers::CompositorChild> nsWindow::sCompositorChild = 0;
|
||||
bool nsWindow::sCompositorPaused = false;
|
||||
bool nsWindow::sCompositorPaused = true;
|
||||
|
||||
void
|
||||
nsWindow::SetCompositor(mozilla::layers::LayerManager* aLayerManager,
|
||||
|
@ -139,6 +139,7 @@ public:
|
||||
LayersBackend aBackendHint = mozilla::layers::LAYERS_NONE,
|
||||
LayerManagerPersistence aPersistence = LAYER_MANAGER_CURRENT,
|
||||
bool* aAllowRetaining = nullptr);
|
||||
void CreateLayerManager();
|
||||
|
||||
NS_IMETHOD ReparentNativeWidget(nsIWidget* aNewParent);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user