Commit b4fc81bd authored by Ken Thomases's avatar Ken Thomases Committed by Alexandre Julliard

winemac: Stop the CVDisplayLink when there are no more changes to flush.

The change to a CVDisplayLink-driven display mechanism introduced a problem: a Wine process never went completely idle for long periods. The display link would fire for every refresh cycle of the display, waking a CPU from idle and wasting energy. To fix that, I have the display link stop itself when it determines that none of its windows need to be displayed. When a window is subsequently marked as needing display, it either temporarily re-enables Cocoa's normal autodisplay mechanism so that it displays at the end of the current turn of the run loop, or it restarts the display link. It chooses the former if it's been a long time since the window was last displayed so that the display is done more immediately. Signed-off-by: 's avatarKen Thomases <ken@codeweavers.com> Signed-off-by: 's avatarAlexandre Julliard <julliard@winehq.org>
parent d6574111
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
pthread_mutex_t* surface_mutex; pthread_mutex_t* surface_mutex;
CGDirectDisplayID _lastDisplayID; CGDirectDisplayID _lastDisplayID;
NSTimeInterval _lastDisplayTime;
NSBezierPath* shape; NSBezierPath* shape;
NSData* shapeData; NSData* shapeData;
......
...@@ -161,6 +161,9 @@ static inline NSUInteger adjusted_modifiers_for_option_behavior(NSUInteger modif ...@@ -161,6 +161,9 @@ static inline NSUInteger adjusted_modifiers_for_option_behavior(NSUInteger modif
CGDirectDisplayID _displayID; CGDirectDisplayID _displayID;
CVDisplayLinkRef _link; CVDisplayLinkRef _link;
NSMutableSet* _windows; NSMutableSet* _windows;
NSTimeInterval _actualRefreshPeriod;
NSTimeInterval _nominalRefreshPeriod;
} }
- (id) initWithDisplayID:(CGDirectDisplayID)displayID; - (id) initWithDisplayID:(CGDirectDisplayID)displayID;
...@@ -168,6 +171,10 @@ static inline NSUInteger adjusted_modifiers_for_option_behavior(NSUInteger modif ...@@ -168,6 +171,10 @@ static inline NSUInteger adjusted_modifiers_for_option_behavior(NSUInteger modif
- (void) addWindow:(WineWindow*)window; - (void) addWindow:(WineWindow*)window;
- (void) removeWindow:(WineWindow*)window; - (void) removeWindow:(WineWindow*)window;
- (NSTimeInterval) refreshPeriod;
- (void) start;
@end @end
@implementation WineDisplayLink @implementation WineDisplayLink
...@@ -234,12 +241,41 @@ static CVReturn WineDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTi ...@@ -234,12 +241,41 @@ static CVReturn WineDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTi
windows = [_windows copy]; windows = [_windows copy];
} }
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
BOOL anyDisplayed = FALSE;
for (WineWindow* window in windows) for (WineWindow* window in windows)
[window displayIfNeeded]; {
if ([window viewsNeedDisplay])
{
[window displayIfNeeded];
anyDisplayed = YES;
}
}
if (!anyDisplayed)
CVDisplayLinkStop(_link);
}); });
[windows release]; [windows release];
} }
- (NSTimeInterval) refreshPeriod
{
if (_actualRefreshPeriod || (_actualRefreshPeriod = CVDisplayLinkGetActualOutputVideoRefreshPeriod(_link)))
return _actualRefreshPeriod;
if (_nominalRefreshPeriod)
return _nominalRefreshPeriod;
CVTime time = CVDisplayLinkGetNominalOutputVideoRefreshPeriod(_link);
if (time.flags & kCVTimeIsIndefinite)
return 1.0 / 60.0;
_nominalRefreshPeriod = time.timeValue / (double)time.timeScale;
return _nominalRefreshPeriod;
}
- (void) start
{
CVDisplayLinkStart(_link);
}
static CVReturn WineDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp* inNow, const CVTimeStamp* inOutputTime, CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void* displayLinkContext) static CVReturn WineDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp* inNow, const CVTimeStamp* inOutputTime, CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void* displayLinkContext)
{ {
WineDisplayLink* link = displayLinkContext; WineDisplayLink* link = displayLinkContext;
...@@ -690,6 +726,7 @@ static CVReturn WineDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTi ...@@ -690,6 +726,7 @@ static CVReturn WineDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTi
window->savedContentMinSize = NSZeroSize; window->savedContentMinSize = NSZeroSize;
window->savedContentMaxSize = NSMakeSize(FLT_MAX, FLT_MAX); window->savedContentMaxSize = NSMakeSize(FLT_MAX, FLT_MAX);
window->resizable = wf->resizable; window->resizable = wf->resizable;
window->_lastDisplayTime = [[NSDate distantPast] timeIntervalSinceReferenceDate];
[window registerForDraggedTypes:[NSArray arrayWithObjects:(NSString*)kUTTypeData, [window registerForDraggedTypes:[NSArray arrayWithObjects:(NSString*)kUTTypeData,
(NSString*)kUTTypeContent, (NSString*)kUTTypeContent,
...@@ -1663,21 +1700,8 @@ static CVReturn WineDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTi ...@@ -1663,21 +1700,8 @@ static CVReturn WineDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTi
} }
} }
- (void) checkWineDisplayLink - (NSMutableDictionary*) displayIDToDisplayLinkMap
{ {
NSScreen* screen = self.screen;
if (![self isVisible] || ![self isOnActiveSpace] || [self isMiniaturized] || [self isEmptyShaped])
screen = nil;
#if defined(MAC_OS_X_VERSION_10_9) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
if ([self respondsToSelector:@selector(occlusionState)] && !(self.occlusionState & NSWindowOcclusionStateVisible))
screen = nil;
#endif
NSNumber* displayIDNumber = [screen.deviceDescription objectForKey:@"NSScreenNumber"];
CGDirectDisplayID displayID = [displayIDNumber unsignedIntValue];
if (displayID == _lastDisplayID)
return;
static NSMutableDictionary* displayIDToDisplayLinkMap; static NSMutableDictionary* displayIDToDisplayLinkMap;
if (!displayIDToDisplayLinkMap) if (!displayIDToDisplayLinkMap)
{ {
...@@ -1693,6 +1717,34 @@ static CVReturn WineDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTi ...@@ -1693,6 +1717,34 @@ static CVReturn WineDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTi
[displayIDToDisplayLinkMap removeObjectsForKeys:[badDisplayIDs allObjects]]; [displayIDToDisplayLinkMap removeObjectsForKeys:[badDisplayIDs allObjects]];
}]; }];
} }
return displayIDToDisplayLinkMap;
}
- (WineDisplayLink*) wineDisplayLink
{
if (!_lastDisplayID)
return nil;
NSMutableDictionary* displayIDToDisplayLinkMap = [self displayIDToDisplayLinkMap];
return [displayIDToDisplayLinkMap objectForKey:[NSNumber numberWithUnsignedInt:_lastDisplayID]];
}
- (void) checkWineDisplayLink
{
NSScreen* screen = self.screen;
if (![self isVisible] || ![self isOnActiveSpace] || [self isMiniaturized] || [self isEmptyShaped])
screen = nil;
#if defined(MAC_OS_X_VERSION_10_9) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
if ([self respondsToSelector:@selector(occlusionState)] && !(self.occlusionState & NSWindowOcclusionStateVisible))
screen = nil;
#endif
NSNumber* displayIDNumber = [screen.deviceDescription objectForKey:@"NSScreenNumber"];
CGDirectDisplayID displayID = [displayIDNumber unsignedIntValue];
if (displayID == _lastDisplayID)
return;
NSMutableDictionary* displayIDToDisplayLinkMap = [self displayIDToDisplayLinkMap];
if (_lastDisplayID) if (_lastDisplayID)
{ {
...@@ -2026,6 +2078,40 @@ static CVReturn WineDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTi ...@@ -2026,6 +2078,40 @@ static CVReturn WineDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTi
[super toggleFullScreen:sender]; [super toggleFullScreen:sender];
} }
- (void) setViewsNeedDisplay:(BOOL)value
{
if (value && ![self viewsNeedDisplay])
{
WineDisplayLink* link = [self wineDisplayLink];
if (link)
{
NSTimeInterval now = [[NSProcessInfo processInfo] systemUptime];
if (_lastDisplayTime + [link refreshPeriod] < now)
[self setAutodisplay:YES];
else
{
[link start];
_lastDisplayTime = now;
}
}
}
[super setViewsNeedDisplay:value];
}
- (void) display
{
_lastDisplayTime = [[NSProcessInfo processInfo] systemUptime];
[super display];
[self setAutodisplay:NO];
}
- (void) displayIfNeeded
{
_lastDisplayTime = [[NSProcessInfo processInfo] systemUptime];
[super displayIfNeeded];
[self setAutodisplay:NO];
}
- (NSArray*) childWineWindows - (NSArray*) childWineWindows
{ {
NSArray* childWindows = self.childWindows; NSArray* childWindows = self.childWindows;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment