diff options
author | Julian Rex <julian.rex@mapbox.com> | 2018-03-27 09:54:57 -0400 |
---|---|---|
committer | Julian Rex <julian.rex@mapbox.com> | 2018-03-27 10:10:13 -0400 |
commit | f23c700c29876566376a13b651e54718f3f1e74c (patch) | |
tree | 72729e0eefc8a5f7284e742a0f08bc6812ad5631 | |
parent | 4f196d48ddfc3bb05dee1cdd032af170a6c53d67 (diff) |
Add CVDisplayLink update, similar to CADisplayLink Refs #11275upstream/jrex-11275-render-display-link-test
-rw-r--r-- | platform/macos/src/MGLMapView.mm | 79 |
1 files changed, 74 insertions, 5 deletions
diff --git a/platform/macos/src/MGLMapView.mm b/platform/macos/src/MGLMapView.mm index 9cab9a76d..9a96e0928 100644 --- a/platform/macos/src/MGLMapView.mm +++ b/platform/macos/src/MGLMapView.mm @@ -131,6 +131,9 @@ mbgl::util::UnitBezier MGLUnitBezierForMediaTimingFunction(CAMediaTimingFunction return { p1[0], p1[1], p2[0], p2[1] }; } +/// Forward declaration of render callback function called via CVDisplayLink +static CVReturn MGLMapViewRenderCallback(CVDisplayLinkRef displayLink, const CVTimeStamp *inNow, const CVTimeStamp *inOutputTime, CVOptionFlags flagsIn, CVOptionFlags *flagsOut, void *displayLinkContext); + /// Lightweight container for metadata about an annotation, including the annotation itself. class MGLAnnotationContext { public: @@ -207,6 +210,10 @@ public: /// reachability instance MGLReachability *_reachability; + + // Display update + CVDisplayLinkRef _displayLink; + BOOL _needsDisplayRefresh; } #pragma mark Lifecycle @@ -513,10 +520,10 @@ public: } - (void)dealloc { + [self validateDisplayLink]; [_reachability stopNotifier]; - [self.window removeObserver:self forKeyPath:@"contentLayoutRect"]; [self.window removeObserver:self forKeyPath:@"titlebarAppearsTransparent"]; @@ -663,19 +670,56 @@ public: self.dormant = YES; } + [self validateDisplayLink]; + [self.window removeObserver:self forKeyPath:@"contentLayoutRect"]; [self.window removeObserver:self forKeyPath:@"titlebarAppearsTransparent"]; } +- (void)validateDisplayLink +{ + BOOL isVisible = self.superview && self.window; + if (isVisible && !_displayLink) + { + if (_mbglMap->getConstrainMode() == mbgl::ConstrainMode::None) + { + _mbglMap->setConstrainMode(mbgl::ConstrainMode::HeightOnly); + } + + CVReturn error = CVDisplayLinkCreateWithCGDisplay(CGMainDisplayID(), &_displayLink); + + if (error) + { + throw std::runtime_error("Failed to create display callback."); + _displayLink = NULL; + } + else + { + CVDisplayLinkSetOutputCallback(_displayLink, MGLMapViewRenderCallback, (__bridge void *)self); + _needsDisplayRefresh = YES; + CVDisplayLinkStart(_displayLink); + } + } + else if ( ! isVisible && _displayLink) + { + CVDisplayLinkStop(_displayLink); + CVDisplayLinkRelease(_displayLink); + _displayLink = nil; + } +} + + - (void)viewDidMoveToWindow { NSWindow *window = self.window; if (self.dormant && window) { self.dormant = NO; } - if (window && _mbglMap->getConstrainMode() == mbgl::ConstrainMode::None) { - _mbglMap->setConstrainMode(mbgl::ConstrainMode::HeightOnly); - } + [self validateDisplayLink]; + +// if (window && _mbglMap->getConstrainMode() == mbgl::ConstrainMode::None) { +// _mbglMap->setConstrainMode(mbgl::ConstrainMode::HeightOnly); +// } [window addObserver:self forKeyPath:@"contentLayoutRect" @@ -795,10 +839,21 @@ public: } } +- (void)updateFromDisplayLink +{ + MGLAssertIsMainThread(); + + if (_needsDisplayRefresh) + { + _needsDisplayRefresh = NO; + [self.layer setNeedsDisplay]; + } +} + - (void)setNeedsGLDisplay { MGLAssertIsMainThread(); - [self.layer setNeedsDisplay]; + _needsDisplayRefresh = YES; } - (void)cameraWillChangeAnimated:(BOOL)animated { @@ -3024,3 +3079,17 @@ private: }; @end + +CVReturn MGLMapViewRenderCallback(CVDisplayLinkRef displayLink, + const CVTimeStamp *inNow, + const CVTimeStamp *inOutputTime, + CVOptionFlags flagsIn, + CVOptionFlags *flagsOut, + void *displayLinkContext) { + dispatch_async(dispatch_get_main_queue(), ^{ + [(__bridge MGLMapView *)displayLinkContext updateFromDisplayLink]; + }); + + return kCVReturnSuccess; +} + |