From 530cf3dcbb78b1759f09a0913b3df48e0d2dce79 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 16 Jun 2016 18:04:54 -0400 Subject: [PATCH] Made an attempt to consolidate serialisation and clock rate adherence, allowing a floating-point clock rate. --- .../Clock Signal.xcodeproj/project.pbxproj | 16 ++++- .../Updater/CSBestEffortUpdater.h | 28 ++++++++ .../Updater/CSBestEffortUpdater.m | 65 +++++++++++++++++++ 3 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 OSBindings/Mac/Clock Signal/Updater/CSBestEffortUpdater.h create mode 100644 OSBindings/Mac/Clock Signal/Updater/CSBestEffortUpdater.m diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index d15dea70e..057575c69 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -318,6 +318,7 @@ 4BC9DF451D044FCA00F44158 /* ROMImages in Resources */ = {isa = PBXBuildFile; fileRef = 4BC9DF441D044FCA00F44158 /* ROMImages */; }; 4BC9DF4F1D04691600F44158 /* 6560.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC9DF4D1D04691600F44158 /* 6560.cpp */; }; 4BCA98C31D065CA20062F44C /* 6522.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BCA98C11D065CA20062F44C /* 6522.cpp */; }; + 4BD5F1951D13528900631CD1 /* CSBestEffortUpdater.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BD5F1941D13528900631CD1 /* CSBestEffortUpdater.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -692,6 +693,8 @@ 4BC9DF4E1D04691600F44158 /* 6560.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = 6560.hpp; sourceTree = ""; }; 4BCA98C11D065CA20062F44C /* 6522.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = 6522.cpp; sourceTree = ""; }; 4BCA98C21D065CA20062F44C /* 6522.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = 6522.hpp; sourceTree = ""; }; + 4BD5F1931D13528900631CD1 /* CSBestEffortUpdater.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CSBestEffortUpdater.h; path = Updater/CSBestEffortUpdater.h; sourceTree = ""; }; + 4BD5F1941D13528900631CD1 /* CSBestEffortUpdater.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CSBestEffortUpdater.m; path = Updater/CSBestEffortUpdater.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -1192,6 +1195,7 @@ 4BB73EA01B587A5100552FC2 /* Clock Signal */ = { isa = PBXGroup; children = ( + 4BE5F85A1C3E1C2500C43F01 /* Resources */, 4BB73ECF1B587A6700552FC2 /* Clock Signal.entitlements */, 4B1414501B58848C00E04248 /* ClockSignal-Bridging-Header.h */, 4BB73EAA1B587A5100552FC2 /* MainMenu.xib */, @@ -1201,7 +1205,7 @@ 4B2A538F1D117D36003C6002 /* Audio */, 4B55CE551C3B7D360093A61B /* Documents */, 4B2A53921D117D36003C6002 /* Machine */, - 4BE5F85A1C3E1C2500C43F01 /* Resources */, + 4BD5F1961D1352A000631CD1 /* Updater */, 4B55CE5A1C3B7D6F0093A61B /* Views */, ); path = "Clock Signal"; @@ -1311,6 +1315,15 @@ path = 6560; sourceTree = ""; }; + 4BD5F1961D1352A000631CD1 /* Updater */ = { + isa = PBXGroup; + children = ( + 4BD5F1931D13528900631CD1 /* CSBestEffortUpdater.h */, + 4BD5F1941D13528900631CD1 /* CSBestEffortUpdater.m */, + ); + name = Updater; + sourceTree = ""; + }; 4BE5F85A1C3E1C2500C43F01 /* Resources */ = { isa = PBXGroup; children = ( @@ -1733,6 +1746,7 @@ 4BC3B74F1CD194CC00F86E85 /* Shader.cpp in Sources */, 4B55CE581C3B7D360093A61B /* Atari2600Document.swift in Sources */, 4BBB14311CD2CECE00BDB55C /* IntermediateShader.cpp in Sources */, + 4BD5F1951D13528900631CD1 /* CSBestEffortUpdater.m in Sources */, 4B73C71A1D036BD90074D992 /* Vic20Document.swift in Sources */, 4BBF99181C8FBA6F0075DAFB /* TextureTarget.cpp in Sources */, 4BC76E691C98E31700E6EF73 /* FIRFilter.cpp in Sources */, diff --git a/OSBindings/Mac/Clock Signal/Updater/CSBestEffortUpdater.h b/OSBindings/Mac/Clock Signal/Updater/CSBestEffortUpdater.h new file mode 100644 index 000000000..eed663901 --- /dev/null +++ b/OSBindings/Mac/Clock Signal/Updater/CSBestEffortUpdater.h @@ -0,0 +1,28 @@ +// +// CSBestEffortUpdater.h +// Clock Signal +// +// Created by Thomas Harte on 16/06/2016. +// Copyright © 2016 Thomas Harte. All rights reserved. +// + +#import +@import CoreVideo; + +@class CSBestEffortUpdater; + +@protocol CSBestEffortUpdaterDelegate + +- (void)bestEffortUpdater:(CSBestEffortUpdater *)bestEffortUpdater runForCycles:(NSUInteger)cycles didSkipPreviousUpdate:(BOOL)didSkipPreviousUpdate; + +@end + + +@interface CSBestEffortUpdater : NSObject + +@property (nonatomic, assign) double clockRate; +@property (nonatomic, weak) id delegate; + +- (void)update; + +@end diff --git a/OSBindings/Mac/Clock Signal/Updater/CSBestEffortUpdater.m b/OSBindings/Mac/Clock Signal/Updater/CSBestEffortUpdater.m new file mode 100644 index 000000000..74f885fe4 --- /dev/null +++ b/OSBindings/Mac/Clock Signal/Updater/CSBestEffortUpdater.m @@ -0,0 +1,65 @@ +// +// CSBestEffortUpdater.m +// Clock Signal +// +// Created by Thomas Harte on 16/06/2016. +// Copyright © 2016 Thomas Harte. All rights reserved. +// + +#import "CSBestEffortUpdater.h" + +@implementation CSBestEffortUpdater +{ + // these are inherently handled only by thread-safe constructions + uint32_t _updateIsOngoing; + dispatch_queue_t _serialDispatchQueue; + + // these are permitted for modification on _serialDispatchQueue only + NSTimeInterval _previousTimeInterval; + NSTimeInterval _cyclesError; + BOOL _hasSkipped; +} + +- (instancetype)init +{ + if(self = [super init]) + { + _serialDispatchQueue = dispatch_queue_create("Best Effort Updater", DISPATCH_QUEUE_SERIAL); + } + return self; +} + +- (void)update +{ + const uint32_t processingMask = 0x01; + + // Always post an -openGLView:didUpdateToTime: if a previous one isn't still ongoing. This is the hook upon which the substantial processing occurs. + if(!OSAtomicTestAndSet(processingMask, &_updateIsOngoing)) + { + dispatch_async(_serialDispatchQueue, ^{ + NSTimeInterval timeInterval = [NSDate timeIntervalSinceReferenceDate]; + if(_previousTimeInterval > DBL_EPSILON) + { + NSTimeInterval timeToRunFor = timeInterval - _previousTimeInterval; + double cyclesToRunFor = timeToRunFor * self.clockRate + _cyclesError; + + _cyclesError = fmod(cyclesToRunFor, 1.0); + NSUInteger integerCyclesToRunFor = (NSUInteger)cyclesToRunFor; + + [self.delegate bestEffortUpdater:self runForCycles:integerCyclesToRunFor didSkipPreviousUpdate:_hasSkipped]; + + _previousTimeInterval = timeInterval; + } + _hasSkipped = NO; + OSAtomicTestAndClear(processingMask, &_updateIsOngoing); + }); + } + else + { + dispatch_async(_serialDispatchQueue, ^{ + _hasSkipped = YES; + }); + } +} + +@end