Bug 1187322 - Don't require accelerated OpenGL contexts for BasicCompositor on OS X. r?jrmuizel draft
authorMarkus Stange <mstange@themasta.com>
Wed, 23 Dec 2015 16:22:55 +0100
changeset 317196 bd692fcbb31e07afdb37f53d5197ea81b1b6885b
parent 317192 e3007cc020e26cb8532f6f380a45ddb7e63e2c8c
child 512276 a3701ee7946b64767a3c33310b922dbc00f157a6
push id8676
push usermstange@themasta.com
push dateWed, 23 Dec 2015 15:27:56 +0000
reviewersjrmuizel
bugs1187322
milestone46.0a1
Bug 1187322 - Don't require accelerated OpenGL contexts for BasicCompositor on OS X. r?jrmuizel
gfx/gl/GLContextProviderCGL.mm
gfx/gl/GLContextProviderEAGL.mm
gfx/gl/GLContextProviderEGL.cpp
gfx/gl/GLContextProviderGLX.cpp
gfx/gl/GLContextProviderImpl.h
gfx/gl/GLContextProviderNull.cpp
gfx/gl/GLContextProviderWGL.cpp
gfx/layers/opengl/CompositorOGL.cpp
gfx/thebes/gfxPlatform.cpp
gfx/thebes/gfxPlatform.h
gfx/thebes/gfxPlatformMac.h
modules/libpref/init/all.js
widget/cocoa/nsChildView.mm
--- a/gfx/gl/GLContextProviderCGL.mm
+++ b/gfx/gl/GLContextProviderCGL.mm
@@ -12,16 +12,20 @@
 #include "gfxFailure.h"
 #include "gfxPrefs.h"
 #include "prenv.h"
 #include "GeckoProfiler.h"
 #include "mozilla/gfx/MacIOSurface.h"
 
 #include <OpenGL/OpenGL.h>
 
+// When running inside a VM, creating an accelerated OpenGL context usually
+// fails. Uncomment this line to emulate that behavior.
+// #define EMULATE_VM
+
 namespace mozilla {
 namespace gl {
 
 using namespace mozilla::gfx;
 
 class CGLLibrary
 {
 public:
@@ -169,22 +173,33 @@ GLContextCGL::SwapBuffers()
 
 already_AddRefed<GLContext>
 GLContextProviderCGL::CreateWrappingExisting(void*, void*)
 {
     return nullptr;
 }
 
 static const NSOpenGLPixelFormatAttribute kAttribs_singleBuffered[] = {
+    NSOpenGLPFAAllowOfflineRenderers,
+    0
+};
+
+static const NSOpenGLPixelFormatAttribute kAttribs_singleBuffered_accel[] = {
     NSOpenGLPFAAccelerated,
     NSOpenGLPFAAllowOfflineRenderers,
     0
 };
 
 static const NSOpenGLPixelFormatAttribute kAttribs_doubleBuffered[] = {
+    NSOpenGLPFAAllowOfflineRenderers,
+    NSOpenGLPFADoubleBuffer,
+    0
+};
+
+static const NSOpenGLPixelFormatAttribute kAttribs_doubleBuffered_accel[] = {
     NSOpenGLPFAAccelerated,
     NSOpenGLPFAAllowOfflineRenderers,
     NSOpenGLPFADoubleBuffer,
     0
 };
 
 static const NSOpenGLPixelFormatAttribute kAttribs_offscreen[] = {
     0
@@ -220,27 +235,33 @@ CreateWithFormat(const NSOpenGLPixelForm
                                 shareContext:nullptr];
 
     [format release];
 
     return context;
 }
 
 already_AddRefed<GLContext>
-GLContextProviderCGL::CreateForWindow(nsIWidget *aWidget)
+GLContextProviderCGL::CreateForWindow(nsIWidget *aWidget, bool aForceAccelerated)
 {
     if (!sCGLLibrary.EnsureInitialized()) {
         return nullptr;
     }
 
+#ifdef EMULATE_VM
+    if (aForceAccelerated) {
+        return nullptr;
+    }
+#endif
+
     const NSOpenGLPixelFormatAttribute* attribs;
     if (sCGLLibrary.UseDoubleBufferedWindows()) {
-        attribs = kAttribs_doubleBuffered;
+        attribs = aForceAccelerated ? kAttribs_doubleBuffered_accel : kAttribs_doubleBuffered;
     } else {
-        attribs = kAttribs_singleBuffered;
+        attribs = aForceAccelerated ? kAttribs_singleBuffered_accel : kAttribs_singleBuffered;
     }
     NSOpenGLContext* context = CreateWithFormat(attribs);
     if (!context) {
         return nullptr;
     }
 
     // make the context transparent
     GLint opaque = 0;
--- a/gfx/gl/GLContextProviderEAGL.mm
+++ b/gfx/gl/GLContextProviderEAGL.mm
@@ -206,17 +206,17 @@ CreateEAGLContext(bool aOffscreen, GLCon
         glContext = nullptr;
         return nullptr;
     }
 
     return glContext.forget();
 }
 
 already_AddRefed<GLContext>
-GLContextProviderEAGL::CreateForWindow(nsIWidget* aWidget)
+GLContextProviderEAGL::CreateForWindow(nsIWidget* aWidget, bool aForceAccelerated)
 {
     RefPtr<GLContext> glContext = CreateEAGLContext(false, GetGlobalContextEAGL());
     if (!glContext) {
         return nullptr;
     }
 
     if (!GLContextEAGL::Cast(glContext)->AttachToWindow(aWidget)) {
         return nullptr;
--- a/gfx/gl/GLContextProviderEGL.cpp
+++ b/gfx/gl/GLContextProviderEGL.cpp
@@ -758,17 +758,17 @@ GLContextProviderEGL::CreateWrappingExis
 
         return glContext.forget();
     }
 
     return nullptr;
 }
 
 already_AddRefed<GLContext>
-GLContextProviderEGL::CreateForWindow(nsIWidget *aWidget)
+GLContextProviderEGL::CreateForWindow(nsIWidget *aWidget, bool aForceAccelerated)
 {
     if (!sEGLLibrary.EnsureInitialized()) {
         MOZ_CRASH("GFX: Failed to load EGL library 3!\n");
         return nullptr;
     }
 
     bool doubleBuffered = true;
 
--- a/gfx/gl/GLContextProviderGLX.cpp
+++ b/gfx/gl/GLContextProviderGLX.cpp
@@ -1047,17 +1047,17 @@ GLContextProviderGLX::CreateWrappingExis
 
         return glContext.forget();
     }
 
     return nullptr;
 }
 
 already_AddRefed<GLContext>
-GLContextProviderGLX::CreateForWindow(nsIWidget *aWidget)
+GLContextProviderGLX::CreateForWindow(nsIWidget *aWidget, bool aForceAccelerated)
 {
     if (!sGLXLibrary.EnsureInitialized()) {
         return nullptr;
     }
 
     // Currently, we take whatever Visual the window already has, and
     // try to create an fbconfig for that visual.  This isn't
     // necessarily what we want in the long run; an fbconfig may not
--- a/gfx/gl/GLContextProviderImpl.h
+++ b/gfx/gl/GLContextProviderImpl.h
@@ -30,21 +30,22 @@ public:
      * The GetSharedContext() method will return non-null if sharing
      * was successful.
      *
      * Note: a context created for a widget /must not/ hold a strong
      * reference to the widget; otherwise a cycle can be created through
      * a GL layer manager.
      *
      * @param aWidget Widget whose surface to create a context for
+     * @param aForceAccelerated true if only accelerated contexts are allowed
      *
      * @return Context to use for the window
      */
     static already_AddRefed<GLContext>
-    CreateForWindow(nsIWidget* widget);
+    CreateForWindow(nsIWidget* widget, bool aForceAccelerated);
 
     /**
      * Create a context for offscreen rendering.  The target of this
      * context should be treated as opaque -- it might be a FBO, or a
      * pbuffer, or some other construct.  Users of this GLContext
      * should bind framebuffer 0 directly to use this offscreen buffer.
      *
      * The offscreen context returned by this method will always have
--- a/gfx/gl/GLContextProviderNull.cpp
+++ b/gfx/gl/GLContextProviderNull.cpp
@@ -4,17 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "GLContextProvider.h"
 
 namespace mozilla {
 namespace gl {
 
 already_AddRefed<GLContext>
-GLContextProviderNull::CreateForWindow(nsIWidget*)
+GLContextProviderNull::CreateForWindow(nsIWidget*, bool aForceAccelerated)
 {
     return nullptr;
 }
 
 already_AddRefed<GLContext>
 GLContextProviderNull::CreateWrappingExisting(void*, void*)
 {
     return nullptr;
--- a/gfx/gl/GLContextProviderWGL.cpp
+++ b/gfx/gl/GLContextProviderWGL.cpp
@@ -433,17 +433,17 @@ GetGlobalContextWGL()
 
 already_AddRefed<GLContext>
 GLContextProviderWGL::CreateWrappingExisting(void*, void*)
 {
     return nullptr;
 }
 
 already_AddRefed<GLContext>
-GLContextProviderWGL::CreateForWindow(nsIWidget *aWidget)
+GLContextProviderWGL::CreateForWindow(nsIWidget *aWidget, bool aForceAccelerated)
 {
     if (!sWGLLib.EnsureInitialized()) {
         return nullptr;
     }
 
     /**
        * We need to make sure we call SetPixelFormat -after- calling
        * EnsureInitialized, otherwise it can load/unload the dll and
--- a/gfx/layers/opengl/CompositorOGL.cpp
+++ b/gfx/layers/opengl/CompositorOGL.cpp
@@ -102,32 +102,33 @@ CompositorOGL::CreateContext()
   if (widgetOpenGLContext) {
     GLContext* alreadyRefed = reinterpret_cast<GLContext*>(widgetOpenGLContext);
     return already_AddRefed<GLContext>(alreadyRefed);
   }
 
 #ifdef XP_WIN
   if (gfxEnv::LayersPreferEGL()) {
     printf_stderr("Trying GL layers...\n");
-    context = gl::GLContextProviderEGL::CreateForWindow(mWidget);
+    context = gl::GLContextProviderEGL::CreateForWindow(mWidget, false);
   }
 #endif
 
   // Allow to create offscreen GL context for main Layer Manager
   if (!context && gfxEnv::LayersPreferOffscreen()) {
     SurfaceCaps caps = SurfaceCaps::ForRGB();
     caps.preserve = false;
     caps.bpp16 = gfxPlatform::GetPlatform()->GetOffscreenFormat() == gfxImageFormat::RGB16_565;
 
     context = GLContextProvider::CreateOffscreen(mSurfaceSize,
                                                  caps, CreateContextFlags::REQUIRE_COMPAT_PROFILE);
   }
 
   if (!context) {
-    context = gl::GLContextProvider::CreateForWindow(mWidget);
+    context = gl::GLContextProvider::CreateForWindow(mWidget,
+                gfxPlatform::GetPlatform()->RequiresAcceleratedGLContextForCompositorOGL());
   }
 
   if (!context) {
     NS_WARNING("Failed to create CompositorOGL context");
   }
 
 #ifdef MOZ_WIDGET_GONK
   mWidget->SetNativeData(NS_NATIVE_OPENGL_CONTEXT,
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -2241,19 +2241,17 @@ gfxPlatform::GetAcceleratedCompositorBac
 }
 
 void
 gfxPlatform::GetCompositorBackends(bool useAcceleration, nsTArray<mozilla::layers::LayersBackend>& aBackends)
 {
   if (useAcceleration) {
     GetAcceleratedCompositorBackends(aBackends);
   }
-  if (SupportsBasicCompositor()) {
-    aBackends.AppendElement(LayersBackend::LAYERS_BASIC);
-  }
+  aBackends.AppendElement(LayersBackend::LAYERS_BASIC);
 }
 
 void
 gfxPlatform::NotifyCompositorCreated(LayersBackend aBackend)
 {
   if (mCompositorBackend == aBackend) {
     return;
   }
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -639,36 +639,37 @@ public:
     // devices. Currently this is only used on Windows.
     virtual void GetDeviceInitData(mozilla::gfx::DeviceInitData* aOut);
 
     // Plugin async drawing support.
     virtual bool SupportsPluginDirectBitmapDrawing() {
       return false;
     }
 
+    // Some platforms don't support CompositorOGL in an unaccelerated OpenGL
+    // context. These platforms should return true here.
+    virtual bool RequiresAcceleratedGLContextForCompositorOGL() const {
+      return false;
+    }
+
 protected:
     gfxPlatform();
     virtual ~gfxPlatform();
 
     /**
      * Initialized hardware vsync based on each platform.
      */
     virtual already_AddRefed<mozilla::gfx::VsyncSource> CreateHardwareVsyncSource();
 
     // Returns whether or not layers should be accelerated by default on this platform.
     virtual bool AccelerateLayersByDefault();
 
     // Returns a prioritized list of available compositor backends for acceleration.
     virtual void GetAcceleratedCompositorBackends(nsTArray<mozilla::layers::LayersBackend>& aBackends);
 
-    // Returns whether or not the basic compositor is supported.
-    virtual bool SupportsBasicCompositor() const {
-      return true;
-    }
-
     /**
      * Initialise the preferred and fallback canvas backends
      * aBackendBitmask specifies the backends which are acceptable to the caller.
      * The backend used is determined by aBackendBitmask and the order specified
      * by the gfx.canvas.azure.backends pref.
      */
     void InitBackendPrefs(uint32_t aCanvasBitmask, mozilla::gfx::BackendType aCanvasDefault,
                           uint32_t aContentBitmask, mozilla::gfx::BackendType aContentDefault);
--- a/gfx/thebes/gfxPlatformMac.h
+++ b/gfx/thebes/gfxPlatformMac.h
@@ -78,19 +78,21 @@ public:
     virtual bool CanRenderContentToDataSurface() const override {
       return true;
     }
 
     virtual bool SupportsApzWheelInput() const override {
       return true;
     }
 
-    bool SupportsBasicCompositor() const override {
-      // At the moment, BasicCompositor is broken on mac.
-      return false;
+    bool RequiresAcceleratedGLContextForCompositorOGL() const override {
+      // On OS X in a VM, unaccelerated CompositorOGL shows black flashes, so we
+      // require accelerated GL for CompositorOGL but allow unaccelerated GL for
+      // BasicCompositor.
+      return true;
     }
 
     bool UseAcceleratedCanvas();
 
     virtual bool UseProgressivePaint() override;
     virtual already_AddRefed<mozilla::gfx::VsyncSource> CreateHardwareVsyncSource() override;
 
     // lower threshold on font anti-aliasing
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -4326,19 +4326,16 @@ pref("layers.tiled-drawtarget.enabled", 
 pref("layers.tiled-drawtarget.enabled", true);
 pref("layers.tiles.edge-padding", true);
 #endif
 
 // same effect as layers.offmainthreadcomposition.enabled, but specifically for
 // use with tests.
 pref("layers.offmainthreadcomposition.testing.enabled", false);
 
-// whether to allow use of the basic compositor
-pref("layers.offmainthreadcomposition.force-basic", false);
-
 // Whether to animate simple opacity and transforms on the compositor
 pref("layers.offmainthreadcomposition.async-animations", true);
 
 // Whether to log information about off main thread animations to stderr
 pref("layers.offmainthreadcomposition.log-animations", false);
 
 pref("layers.bufferrotation.enabled", true);
 
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -331,17 +331,19 @@ protected:
 // We need to use OpenGL for this because there seems to be no other robust
 // way of drawing from a secondary thread without locking, which would cause
 // deadlocks in our setup. See bug 882523.
 class GLPresenter : public GLManager
 {
 public:
   static GLPresenter* CreateForWindow(nsIWidget* aWindow)
   {
-    RefPtr<GLContext> context = gl::GLContextProvider::CreateForWindow(aWindow);
+    // Contrary to CompositorOGL, we allow unaccelerated OpenGL contexts to be
+    // used. BasicCompositor only requires very basic GL functionality.
+    RefPtr<GLContext> context = gl::GLContextProvider::CreateForWindow(aWindow, false);
     return context ? new GLPresenter(context) : nullptr;
   }
 
   explicit GLPresenter(GLContext* aContext);
   virtual ~GLPresenter();
 
   virtual GLContext* gl() const override { return mGLContext; }
   virtual ShaderProgramOGL* GetProgram(GLenum aTarget, gfx::SurfaceFormat aFormat) override