Bug 886999 - Lock the GL context before compositing on the compositor thread or before calling setView or update on the main thread. r=mattwoodrow
☠☠ backed out by 3eefb8a63b65 ☠ ☠
authorMarkus Stange <mstange@themasta.com>
Wed, 09 Oct 2013 10:39:23 -0400
changeset 164067 34d9056bf553afaefefd38f36076fc3046f19bd9
parent 164066 3f053c13cf4ea3abf56cd194968a6319ac763416
child 164068 058c2432bff505b0c22c5f4e42af6ad6cb137c06
push id3066
push userakeybl@mozilla.com
push dateMon, 09 Dec 2013 19:58:46 +0000
treeherdermozilla-beta@a31a0dce83aa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs886999
milestone27.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 886999 - Lock the GL context before compositing on the compositor thread or before calling setView or update on the main thread. r=mattwoodrow
gfx/layers/composite/LayerManagerComposite.cpp
widget/cocoa/nsChildView.h
widget/cocoa/nsChildView.mm
widget/nsIWidget.h
widget/xpwidgets/nsBaseWidget.h
--- a/gfx/layers/composite/LayerManagerComposite.cpp
+++ b/gfx/layers/composite/LayerManagerComposite.cpp
@@ -341,16 +341,17 @@ LayerManagerComposite::Render()
     mCompositor->BeginFrame(&rect, mWorldMatrix, bounds, nullptr, &actualBounds);
   } else {
     gfx::Rect rect;
     mCompositor->BeginFrame(nullptr, mWorldMatrix, bounds, &rect, &actualBounds);
     clipRect = nsIntRect(rect.x, rect.y, rect.width, rect.height);
   }
 
   if (actualBounds.IsEmpty()) {
+    mCompositor->GetWidget()->PostRender(this);
     return;
   }
 
   // Allow widget to render a custom background.
   mCompositor->SaveState();
   mCompositor->GetWidget()->DrawWindowUnderlay(this, nsIntRect(actualBounds.x,
                                                                actualBounds.y,
                                                                actualBounds.width,
@@ -370,16 +371,18 @@ LayerManagerComposite::Render()
 
   // Debugging
   RenderDebugOverlay(actualBounds);
 
   {
     PROFILER_LABEL("LayerManagerComposite", "EndFrame");
     mCompositor->EndFrame();
   }
+
+  mCompositor->GetWidget()->PostRender(this);
 }
 
 void
 LayerManagerComposite::SetWorldTransform(const gfxMatrix& aMatrix)
 {
   NS_ASSERTION(aMatrix.PreservesAxisAlignedRectangles(),
                "SetWorldTransform only accepts matrices that satisfy PreservesAxisAlignedRectangles");
   NS_ASSERTION(!aMatrix.HasNonIntegerScale(),
--- a/widget/cocoa/nsChildView.h
+++ b/widget/cocoa/nsChildView.h
@@ -328,16 +328,17 @@ typedef NSInteger NSEventGestureAxis;
 - (BOOL)isPluginView;
 
 // Are we processing an NSLeftMouseDown event that will fail to click through?
 // If so, we shouldn't focus or unfocus a plugin.
 - (BOOL)isInFailingLeftClickThrough;
 
 - (void)setGLContext:(NSOpenGLContext *)aGLContext;
 - (bool)preRender:(NSOpenGLContext *)aGLContext;
+- (void)postRender:(NSOpenGLContext *)aGLContext;
 
 - (BOOL)isCoveringTitlebar;
 
 // Simple gestures support
 //
 // XXX - The swipeWithEvent, beginGestureWithEvent, magnifyWithEvent,
 // rotateWithEvent, and endGestureWithEvent methods are part of a
 // PRIVATE interface exported by nsResponder and reverse-engineering
@@ -532,16 +533,17 @@ public:
   already_AddRefed<mozilla::a11y::Accessible> GetDocumentAccessible();
 #endif
 
   virtual void CreateCompositor();
   virtual gfxASurface* GetThebesSurface();
   virtual void PrepareWindowEffects() MOZ_OVERRIDE;
   virtual void CleanupWindowEffects() MOZ_OVERRIDE;
   virtual bool PreRender(LayerManager* aManager) MOZ_OVERRIDE;
+  virtual void PostRender(LayerManager* aManager) MOZ_OVERRIDE;
   virtual void DrawWindowOverlay(LayerManager* aManager, nsIntRect aRect) MOZ_OVERRIDE;
 
   virtual void UpdateThemeGeometries(const nsTArray<ThemeGeometry>& aThemeGeometries);
 
   void              HidePlugin();
   void              UpdatePluginPort();
 
   void              ResetParent();
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -2029,16 +2029,27 @@ nsChildView::PreRender(LayerManager* aMa
   if (!manager) {
     return true;
   }
   NSOpenGLContext *glContext = (NSOpenGLContext *)manager->gl()->GetNativeData(GLContext::NativeGLContext);
   return [(ChildView*)mView preRender:glContext];
 }
 
 void
+nsChildView::PostRender(LayerManager* aManager)
+{
+  nsAutoPtr<GLManager> manager(GLManager::CreateGLManager(aManager));
+  if (!manager) {
+    return;
+  }
+  NSOpenGLContext *glContext = (NSOpenGLContext *)manager->gl()->GetNativeData(GLContext::NativeGLContext);
+  [(ChildView*)mView postRender:glContext];
+}
+
+void
 nsChildView::DrawWindowOverlay(LayerManager* aManager, nsIntRect aRect)
 {
   nsAutoPtr<GLManager> manager(GLManager::CreateGLManager(aManager));
   if (manager) {
     DrawWindowOverlay(manager, aRect);
   }
 }
 
@@ -2433,16 +2444,18 @@ nsChildView::DoRemoteComposition(const n
   // Draw the result from the basic compositor.
   mBasicCompositorImage->Draw(mGLPresenter, nsIntPoint(0, 0));
 
   // DrawWindowOverlay doesn't do anything for non-GL, so it didn't paint
   // anything during the basic compositor transaction. Draw the overlay now.
   DrawWindowOverlay(mGLPresenter, aRenderRect);
 
   mGLPresenter->EndFrame();
+
+  [(ChildView*)mView postRender:mGLPresenter->GetNSOpenGLContext()];
 }
 
 #ifdef ACCESSIBILITY
 already_AddRefed<a11y::Accessible>
 nsChildView::GetDocumentAccessible()
 {
   if (!mozilla::a11y::ShouldA11yBeEnabled())
     return nullptr;
@@ -2878,21 +2891,32 @@ NSEvent* gLastDragMouseDownEvent = nil;
     return false;
   }
 
   if (!mGLContext) {
     [self setGLContext:aGLContext];
     [self updateGLContext];
   }
 
+  CGLLockContext((CGLContextObj)[aGLContext CGLContextObj]);
+
   return true;
 
   NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(false);
 }
 
+- (void)postRender:(NSOpenGLContext *)aGLContext
+{
+  NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
+
+  CGLUnlockContext((CGLContextObj)[aGLContext CGLContextObj]);
+
+  NS_OBJC_END_TRY_ABORT_BLOCK;
+}
+
 - (void)dealloc
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
 
   [mGLContext release];
   [mPendingDirtyRects release];
   [mLastMouseDownEvent release];
   [mClickThroughMouseDownEvent release];
@@ -3215,18 +3239,20 @@ NSEvent* gLastDragMouseDownEvent = nil;
 - (BOOL)mouseDownCanMoveWindow
 {
   return [[self window] isMovableByWindowBackground];
 }
 
 -(void)updateGLContext
 {
   if (mGLContext) {
+    CGLLockContext((CGLContextObj)[mGLContext CGLContextObj]);
     [mGLContext setView:self];
     [mGLContext update];
+    CGLUnlockContext((CGLContextObj)[mGLContext CGLContextObj]);
   }
 }
 
 - (void)_surfaceNeedsUpdate:(NSNotification*)notification
 {
    [self updateGLContext];
 }
 
--- a/widget/nsIWidget.h
+++ b/widget/nsIWidget.h
@@ -91,18 +91,18 @@ typedef void* nsNativeWidget;
 #ifdef XP_WIN
 #define NS_NATIVE_TSF_THREAD_MGR       100
 #define NS_NATIVE_TSF_CATEGORY_MGR     101
 #define NS_NATIVE_TSF_DISPLAY_ATTR_MGR 102
 #define NS_NATIVE_ICOREWINDOW          103 // winrt specific
 #endif
 
 #define NS_IWIDGET_IID \
-{ 0x8e2afc1c, 0x7087, 0x4ec2, \
-  { 0xac, 0xc6, 0xd4, 0xf2, 0x3e, 0x13, 0xd2, 0xb7 } }
+{ 0xa1f684e6, 0x2ae1, 0x4513, \
+  { 0xb6, 0x89, 0xf4, 0xd4, 0xfe, 0x9d, 0x2c, 0xdb } }
 
 /*
  * Window shadow styles
  * Also used for the -moz-window-shadow CSS property
  */
 
 #define NS_STYLE_WINDOW_SHADOW_NONE             0
 #define NS_STYLE_WINDOW_SHADOW_DEFAULT          1
@@ -1220,16 +1220,25 @@ class nsIWidget : public nsISupports {
      * not ready to be rendered (for example while the window is closed).
      *
      * Always called from the compositing thread, which may be the main-thread if
      * OMTC is not enabled.
      */
     virtual bool PreRender(LayerManager* aManager) = 0;
 
     /**
+     * Called after rendering using OpenGL. Not called when rendering was
+     * cancelled by a negative return value from PreRender.
+     *
+     * Always called from the compositing thread, which may be the main-thread if
+     * OMTC is not enabled.
+     */
+    virtual void PostRender(LayerManager* aManager) = 0;
+
+    /**
      * Called before the LayerManager draws the layer tree.
      *
      * Always called from the compositing thread, which may be the main-thread if
      * OMTC is not enabled.
      */
     virtual void DrawWindowUnderlay(LayerManager* aManager, nsIntRect aRect) = 0;
 
     /**
--- a/widget/xpwidgets/nsBaseWidget.h
+++ b/widget/xpwidgets/nsBaseWidget.h
@@ -132,16 +132,17 @@ public:
                                           bool* aAllowRetaining = nullptr);
 
   virtual CompositorParent* NewCompositorParent(int aSurfaceWidth, int aSurfaceHeight);
   virtual void            CreateCompositor();
   virtual void            CreateCompositor(int aWidth, int aHeight);
   virtual void            PrepareWindowEffects() {}
   virtual void            CleanupWindowEffects() {}
   virtual bool            PreRender(LayerManager* aManager) { return true; }
+  virtual void            PostRender(LayerManager* aManager) {}
   virtual void            DrawWindowUnderlay(LayerManager* aManager, nsIntRect aRect) {}
   virtual void            DrawWindowOverlay(LayerManager* aManager, nsIntRect aRect) {}
   virtual mozilla::TemporaryRef<mozilla::gfx::DrawTarget> StartRemoteDrawing();
   virtual void            EndRemoteDrawing() { };
   virtual void            CleanupRemoteDrawing() { };
   virtual void            UpdateThemeGeometries(const nsTArray<ThemeGeometry>& aThemeGeometries) {}
   virtual gfxASurface*    GetThebesSurface();
   NS_IMETHOD              SetModal(bool aModal);