Merge pull request #3496 from dreampiggy/temp/try_fix_promotion
Try to fix the SDAnimatedImageView playback speed issue in Promotion devices (iPhone Pro)
This commit is contained in:
commit
748def0a0c
|
@ -3,12 +3,13 @@
|
|||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 46;
|
||||
objectVersion = 52;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
32892E311FAE898C00BE8320 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 32892E301FAE898C00BE8320 /* Assets.xcassets */; };
|
||||
32892E351FAE89FE00BE8320 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 32892E341FAE89FD00BE8320 /* LaunchScreen.storyboard */; };
|
||||
328CA3AB29980A840063950F /* WindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 328CA3AA29980A840063950F /* WindowController.m */; };
|
||||
3E75A9861742DBE700DA412D /* CustomPathImages in Resources */ = {isa = PBXBuildFile; fileRef = 3E75A9851742DBE700DA412D /* CustomPathImages */; };
|
||||
4314D1AA1D0E1181004B36C9 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 4314D1A91D0E1181004B36C9 /* main.m */; };
|
||||
4314D1AD1D0E1181004B36C9 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 4314D1AC1D0E1181004B36C9 /* AppDelegate.m */; };
|
||||
|
@ -136,6 +137,8 @@
|
|||
327E1C604113A7CEC9AC02DB /* Pods-SDWebImage Watch Demo Extension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SDWebImage Watch Demo Extension.debug.xcconfig"; path = "../Pods/Target Support Files/Pods-SDWebImage Watch Demo Extension/Pods-SDWebImage Watch Demo Extension.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
32892E301FAE898C00BE8320 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
32892E341FAE89FD00BE8320 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
328CA3A929980A840063950F /* WindowController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WindowController.h; sourceTree = "<group>"; };
|
||||
328CA3AA29980A840063950F /* WindowController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WindowController.m; sourceTree = "<group>"; };
|
||||
3E75A9851742DBE700DA412D /* CustomPathImages */ = {isa = PBXFileReference; lastKnownFileType = folder; path = CustomPathImages; sourceTree = SOURCE_ROOT; };
|
||||
4314D1A61D0E1181004B36C9 /* SDWebImage TV Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "SDWebImage TV Demo.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
4314D1A91D0E1181004B36C9 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
|
||||
|
@ -275,6 +278,8 @@
|
|||
children = (
|
||||
43A629D11D0DFD000089D7DD /* AppDelegate.h */,
|
||||
43A629D21D0DFD000089D7DD /* AppDelegate.m */,
|
||||
328CA3A929980A840063950F /* WindowController.h */,
|
||||
328CA3AA29980A840063950F /* WindowController.m */,
|
||||
43A629D71D0DFD000089D7DD /* ViewController.h */,
|
||||
43A629D81D0DFD000089D7DD /* ViewController.m */,
|
||||
43A629DA1D0DFD000089D7DD /* Assets.xcassets */,
|
||||
|
@ -804,6 +809,7 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
43A629D91D0DFD000089D7DD /* ViewController.m in Sources */,
|
||||
328CA3AB29980A840063950F /* WindowController.m in Sources */,
|
||||
43A629D61D0DFD000089D7DD /* main.m in Sources */,
|
||||
43A629D31D0DFD000089D7DD /* AppDelegate.m in Sources */,
|
||||
);
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
@interface AppDelegate : NSObject <NSApplicationDelegate>
|
||||
|
||||
@property (strong, nonatomic) NSWindowController *windowController;
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -30,6 +30,12 @@
|
|||
// For HEIC animated image. Animated image is new introduced in iOS 13, but it contains performance issue for now.
|
||||
[[SDImageCodersManager sharedManager] addCoder:[SDImageHEICCoder sharedCoder]];
|
||||
}
|
||||
|
||||
NSStoryboard *mainStoryboard = [NSStoryboard storyboardWithName:@"Main" bundle:nil];
|
||||
NSWindowController *initialController = [mainStoryboard instantiateControllerWithIdentifier:@"MainWindowController"];
|
||||
self.windowController = initialController;
|
||||
[initialController showWindow:self];
|
||||
[initialController.window makeKeyAndOrderFront:self];
|
||||
}
|
||||
|
||||
- (void)applicationWillTerminate:(NSNotification *)aNotification {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="B8D-0N-5wS">
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="21507" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14490.70"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="21507"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
|
@ -651,7 +651,7 @@
|
|||
<!--Window Controller-->
|
||||
<scene sceneID="R2V-B0-nI4">
|
||||
<objects>
|
||||
<windowController id="B8D-0N-5wS" sceneMemberID="viewController">
|
||||
<windowController storyboardIdentifier="MainWindowController" id="B8D-0N-5wS" customClass="WindowController" sceneMemberID="viewController">
|
||||
<window key="window" title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="IQv-IB-iLA">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
|
||||
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface WindowController : NSWindowController
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#import "WindowController.h"
|
||||
|
||||
@implementation WindowController
|
||||
|
||||
@end
|
|
@ -26,7 +26,7 @@ static void * SDWebImageDownloaderOperationKey = &SDWebImageDownloaderOperationK
|
|||
BOOL SDWebImageDownloaderOperationGetCompleted(id<SDWebImageDownloaderOperation> operation) {
|
||||
NSCParameterAssert(operation);
|
||||
NSNumber *value = objc_getAssociatedObject(operation, SDWebImageDownloaderOperationKey);
|
||||
if (value) {
|
||||
if (value != nil) {
|
||||
return value.boolValue;
|
||||
} else {
|
||||
return NO;
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
@property (readonly, nonatomic, weak, nullable) id target;
|
||||
@property (readonly, nonatomic, assign, nonnull) SEL selector;
|
||||
@property (readonly, nonatomic) CFTimeInterval duration;
|
||||
@property (readonly, nonatomic) NSTimeInterval duration; // elapsed time in seconds of previous callback. (or it's first callback, use the time between `start` and callback). Always zero when display link not running
|
||||
@property (readonly, nonatomic) BOOL isRunning;
|
||||
|
||||
+ (nonnull instancetype)displayLinkWithTarget:(nonnull id)target selector:(nonnull SEL)sel;
|
||||
|
|
|
@ -13,15 +13,31 @@
|
|||
#elif SD_IOS || SD_TV
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
#endif
|
||||
#include <mach/mach_time.h>
|
||||
|
||||
#if SD_MAC
|
||||
static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp *inNow, const CVTimeStamp *inOutputTime, CVOptionFlags flagsIn, CVOptionFlags *flagsOut, void *displayLinkContext);
|
||||
#endif
|
||||
|
||||
#if SD_WATCH
|
||||
static CFTimeInterval CACurrentMediaTime(void)
|
||||
{
|
||||
mach_timebase_info_data_t timebase;
|
||||
mach_timebase_info(&timebase);
|
||||
|
||||
uint64_t time = mach_absolute_time();
|
||||
double seconds = (double)time * (double)timebase.numer / (double)timebase.denom / 1e9;
|
||||
return seconds;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define kSDDisplayLinkInterval 1.0 / 60
|
||||
|
||||
@interface SDDisplayLink ()
|
||||
|
||||
@property (nonatomic, assign) NSTimeInterval previousFireTime;
|
||||
@property (nonatomic, assign) NSTimeInterval nextFireTime;
|
||||
|
||||
#if SD_MAC
|
||||
@property (nonatomic, assign) CVDisplayLinkRef displayLink;
|
||||
@property (nonatomic, assign) CVTimeStamp outputTime;
|
||||
|
@ -32,7 +48,6 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt
|
|||
@property (nonatomic, strong) NSTimer *displayLink;
|
||||
@property (nonatomic, strong) NSRunLoop *runloop;
|
||||
@property (nonatomic, copy) NSRunLoopMode runloopMode;
|
||||
@property (nonatomic, assign) NSTimeInterval currentFireDate;
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
@ -78,34 +93,48 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt
|
|||
return displayLink;
|
||||
}
|
||||
|
||||
- (CFTimeInterval)duration {
|
||||
- (NSTimeInterval)duration {
|
||||
NSTimeInterval duration = 0;
|
||||
#if SD_MAC
|
||||
CVTimeStamp outputTime = self.outputTime;
|
||||
NSTimeInterval duration = 0;
|
||||
double periodPerSecond = (double)outputTime.videoTimeScale * outputTime.rateScalar;
|
||||
if (periodPerSecond > 0) {
|
||||
duration = (double)outputTime.videoRefreshPeriod / periodPerSecond;
|
||||
}
|
||||
#elif SD_IOS || SD_TV
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
NSTimeInterval duration = 0;
|
||||
if (@available(iOS 10.0, tvOS 10.0, *)) {
|
||||
duration = self.displayLink.targetTimestamp - CACurrentMediaTime();
|
||||
} else {
|
||||
duration = self.displayLink.duration * self.displayLink.frameInterval;
|
||||
}
|
||||
#pragma clang diagnostic pop
|
||||
#else
|
||||
NSTimeInterval duration = 0;
|
||||
if (self.displayLink.isValid && self.currentFireDate != 0) {
|
||||
NSTimeInterval nextFireDate = CFRunLoopTimerGetNextFireDate((__bridge CFRunLoopTimerRef)self.displayLink);
|
||||
duration = nextFireDate - self.currentFireDate;
|
||||
// iOS 10+/watchOS use `nextTime`
|
||||
if (@available(iOS 10.0, tvOS 10.0, watchOS 2.0, *)) {
|
||||
duration = self.nextFireTime - CACurrentMediaTime();
|
||||
} else {
|
||||
// iOS 9 use `previousTime`
|
||||
duration = CACurrentMediaTime() - self.previousFireTime;
|
||||
}
|
||||
#endif
|
||||
if (duration <= 0) {
|
||||
// When system sleep, the targetTimestamp will mass up, fallback refresh rate
|
||||
if (duration < 0) {
|
||||
#if SD_MAC
|
||||
// Supports Pro display 120Hz
|
||||
CGDirectDisplayID display = CVDisplayLinkGetCurrentCGDisplay(_displayLink);
|
||||
CGDisplayModeRef mode = CGDisplayCopyDisplayMode(display);
|
||||
if (mode) {
|
||||
double refreshRate = CGDisplayModeGetRefreshRate(mode);
|
||||
if (refreshRate > 0) {
|
||||
duration = 1.0 / refreshRate;
|
||||
} else {
|
||||
duration = kSDDisplayLinkInterval;
|
||||
}
|
||||
CGDisplayModeRelease(mode);
|
||||
} else {
|
||||
duration = kSDDisplayLinkInterval;
|
||||
}
|
||||
#elif SD_IOS || SD_TV
|
||||
// Fallback
|
||||
duration = self.displayLink.duration;
|
||||
#else
|
||||
// Watch always 60Hz
|
||||
duration = kSDDisplayLinkInterval;
|
||||
#endif
|
||||
}
|
||||
return duration;
|
||||
}
|
||||
|
||||
|
@ -189,24 +218,25 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt
|
|||
#else
|
||||
[self.displayLink invalidate];
|
||||
#endif
|
||||
self.previousFireTime = 0;
|
||||
self.nextFireTime = 0;
|
||||
}
|
||||
|
||||
- (void)displayLinkDidRefresh:(id)displayLink {
|
||||
#if SD_MAC
|
||||
// CVDisplayLink does not use runloop, but we can provide similar behavior for modes
|
||||
// May use `default` runloop to avoid extra callback when in `eventTracking` (mouse drag, scroll) or `modalPanel` (modal panel)
|
||||
NSString *runloopMode = self.runloopMode;
|
||||
if (![runloopMode isEqualToString:NSRunLoopCommonModes] && ![runloopMode isEqualToString:NSRunLoop.mainRunLoop.currentMode]) {
|
||||
return;
|
||||
#if SD_IOS || SD_TV
|
||||
if (@available(iOS 10.0, tvOS 10.0, *)) {
|
||||
self.nextFireTime = self.displayLink.targetTimestamp;
|
||||
} else {
|
||||
self.previousFireTime = self.displayLink.timestamp;
|
||||
}
|
||||
#endif
|
||||
#if SD_WATCH
|
||||
self.nextFireTime = CFRunLoopTimerGetNextFireDate((__bridge CFRunLoopTimerRef)self.displayLink);
|
||||
#endif
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
|
||||
[_target performSelector:_selector withObject:self];
|
||||
#pragma clang diagnostic pop
|
||||
#if SD_WATCH
|
||||
self.currentFireDate = CFRunLoopTimerGetNextFireDate((__bridge CFRunLoopTimerRef)self.displayLink);
|
||||
#endif
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -215,11 +245,16 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt
|
|||
static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp *inNow, const CVTimeStamp *inOutputTime, CVOptionFlags flagsIn, CVOptionFlags *flagsOut, void *displayLinkContext) {
|
||||
// CVDisplayLink callback is not on main queue
|
||||
SDDisplayLink *object = (__bridge SDDisplayLink *)displayLinkContext;
|
||||
if (inOutputTime) {
|
||||
object.outputTime = *inOutputTime;
|
||||
// CVDisplayLink does not use runloop, but we can provide similar behavior for modes
|
||||
// May use `default` runloop to avoid extra callback when in `eventTracking` (mouse drag, scroll) or `modalPanel` (modal panel)
|
||||
NSString *runloopMode = object.runloopMode;
|
||||
if (![runloopMode isEqualToString:NSRunLoopCommonModes] && ![runloopMode isEqualToString:NSRunLoop.mainRunLoop.currentMode]) {
|
||||
return kCVReturnSuccess;
|
||||
}
|
||||
CVTimeStamp outputTime = inOutputTime ? *inOutputTime : *inNow;
|
||||
__weak SDDisplayLink *weakObject = object;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
weakObject.outputTime = outputTime;
|
||||
[weakObject displayLinkDidRefresh:(__bridge id)(displayLink)];
|
||||
});
|
||||
return kCVReturnSuccess;
|
||||
|
|
|
@ -48,8 +48,6 @@
|
|||
XCTestExpectation *expectation1 = [self expectationWithDescription:@"Display Link Stop"];
|
||||
XCTestExpectation *expectation2 = [self expectationWithDescription:@"Display Link Start"];
|
||||
SDDisplayLink *displayLink = [SDDisplayLink displayLinkWithTarget:self selector:@selector(displayLinkDidRefresh:)];
|
||||
NSTimeInterval duration = displayLink.duration; // Initial value
|
||||
expect(duration).equal(1.0 / 60);
|
||||
[displayLink addToRunLoop:NSRunLoop.mainRunLoop forMode:NSRunLoopCommonModes];
|
||||
[displayLink start];
|
||||
expect(displayLink.isRunning).beTruthy();
|
||||
|
|
Loading…
Reference in New Issue