Bug 1261483 - Only call updateGLContext from the compositor thread to avoid races. r=mstange
authorMatt Woodrow <mwoodrow@mozilla.com>
Thu, 02 Jun 2016 16:58:44 +1200
changeset 341183 151f1d8697dcad008358b355069ce0d79d10dceb
parent 341182 153b81041c1e63717880e425c09423236c7971b6
child 341184 3d68250b133166b7d65dc99c963fac5fa0ef1439
push id1183
push userraliiev@mozilla.com
push dateMon, 05 Sep 2016 20:01:49 +0000
treeherdermozilla-release@3148731bed45 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmstange
bugs1261483
milestone49.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 1261483 - Only call updateGLContext from the compositor thread to avoid races. r=mstange
widget/cocoa/nsChildView.h
widget/cocoa/nsChildView.mm
--- a/widget/cocoa/nsChildView.h
+++ b/widget/cocoa/nsChildView.h
@@ -200,16 +200,20 @@ typedef NSInteger NSEventGestureAxis;
   BOOL mPendingFullDisplay;
   BOOL mPendingDisplay;
 
   // WheelStart/Stop events should always come in pairs. This BOOL records the
   // last received event so that, when we receive one of the events, we make sure
   // to send its pair event first, in case we didn't yet for any reason.
   BOOL mExpectingWheelStop;
 
+  // Set to YES when our GL surface has been updated and we need to call
+  // updateGLContext before we composite.
+  BOOL mNeedsGLUpdate;
+
   // Holds our drag service across multiple drag calls. The reference to the
   // service is obtained when the mouse enters the view and is released when
   // the mouse exits or there is a drop. This prevents us from having to
   // re-establish the connection to the service manager many times per second
   // when handling |draggingUpdated:| messages.
   nsIDragService* mDragService;
 
   NSOpenGLContext *mGLContext;
@@ -271,17 +275,16 @@ typedef NSInteger NSEventGestureAxis;
 
 - (void)sendMouseEnterOrExitEvent:(NSEvent*)aEvent
                             enter:(BOOL)aEnter
                          exitFrom:(mozilla::WidgetMouseEvent::ExitFrom)aExitFrom;
 
 - (void)updateGLContext;
 - (void)_surfaceNeedsUpdate:(NSNotification*)notification;
 
-- (void)setGLContext:(NSOpenGLContext *)aGLContext;
 - (bool)preRender:(NSOpenGLContext *)aGLContext;
 - (void)postRender:(NSOpenGLContext *)aGLContext;
 
 - (BOOL)isCoveringTitlebar;
 
 - (void)viewWillStartLiveResize;
 - (void)viewDidEndLiveResize;
 
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -3361,16 +3361,18 @@ NSEvent* gLastDragMouseDownEvent = nil;
     mCumulativeRotation = 0.0;
 
     // We can't call forceRefreshOpenGL here because, in order to work around
     // the bug, it seems we need to have a draw already happening. Therefore,
     // we call it in drawRect:inContext:, when we know that a draw is in
     // progress.
     mDidForceRefreshOpenGL = NO;
 
+    mNeedsGLUpdate = NO;
+
     [self setFocusRingType:NSFocusRingTypeNone];
 
 #ifdef __LP64__
     mCancelSwipeAnimation = nil;
 #endif
 
     mTopLeftCornerMask = NULL;
   }
@@ -3452,27 +3454,19 @@ NSEvent* gLastDragMouseDownEvent = nil;
 // again.
 // This can cause a flash in new windows - bug 631339 - but it's very hard to
 // fix that while maintaining this workaround.
 - (void)forceRefreshOpenGL
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
 
   [mGLContext clearDrawable];
+  CGLLockContext((CGLContextObj)[mGLContext CGLContextObj]);
   [self updateGLContext];
-
-  NS_OBJC_END_TRY_ABORT_BLOCK;
-}
-
-- (void)setGLContext:(NSOpenGLContext *)aGLContext
-{
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
-
-  mGLContext = aGLContext;
-  [mGLContext retain];
+  CGLUnlockContext((CGLContextObj)[mGLContext CGLContextObj]);
 
   NS_OBJC_END_TRY_ABORT_BLOCK;
 }
 
 - (bool)preRender:(NSOpenGLContext *)aGLContext
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
 
@@ -3480,22 +3474,28 @@ NSEvent* gLastDragMouseDownEvent = nil;
       ([[self window] isKindOfClass:[BaseWindow class]] &&
        ![(BaseWindow*)[self window] isVisibleOrBeingShown])) {
     // Before the window is shown, our GL context's front FBO is not
     // framebuffer complete, so we refuse to render.
     return false;
   }
 
   if (!mGLContext) {
-    [self setGLContext:aGLContext];
-    [self updateGLContext];
+    mGLContext = aGLContext;
+    [mGLContext retain];
+    mNeedsGLUpdate = true;
   }
 
   CGLLockContext((CGLContextObj)[aGLContext CGLContextObj]);
 
+  if (mNeedsGLUpdate) {
+    [self updateGLContext];
+    mNeedsGLUpdate = NO;
+  }
+
   return true;
 
   NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(false);
 }
 
 - (void)postRender:(NSOpenGLContext *)aGLContext
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
@@ -3717,27 +3717,27 @@ NSEvent* gLastDragMouseDownEvent = nil;
 {
   // Return YES so that _regionForOpaqueDescendants gets called, where the
   // actual draggable region will be assembled.
   return YES;
 }
 
 -(void)updateGLContext
 {
-  if (mGLContext) {
-    CGLLockContext((CGLContextObj)[mGLContext CGLContextObj]);
-    [mGLContext setView:self];
-    [mGLContext update];
-    CGLUnlockContext((CGLContextObj)[mGLContext CGLContextObj]);
-  }
+  [mGLContext setView:self];
+  [mGLContext update];
 }
 
 - (void)_surfaceNeedsUpdate:(NSNotification*)notification
 {
-   [self updateGLContext];
+  if (mGLContext) {
+    CGLLockContext((CGLContextObj)[mGLContext CGLContextObj]);
+    mNeedsGLUpdate = YES;
+    CGLUnlockContext((CGLContextObj)[mGLContext CGLContextObj]);
+  }
 }
 
 - (BOOL)wantsBestResolutionOpenGLSurface
 {
   return nsCocoaUtils::HiDPIEnabled() ? YES : NO;
 }
 
 - (void)viewDidChangeBackingProperties