1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-06-08 10:52:58 +00:00

Hacks up an [unsafe] return to something best-effort-updater-esque.

For profiling, mainly.
This commit is contained in:
Thomas Harte 2022-07-07 16:35:45 -04:00
parent 01a309909b
commit 3e2a6ef3f4
4 changed files with 54 additions and 21 deletions

View File

@ -20,6 +20,11 @@ inline Nanos nanos_now() {
return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count();
}
inline Seconds seconds(Nanos nanos) {
return double(nanos) / 1e9;
}
}
#endif /* TimeTypes_h */

View File

@ -20,7 +20,7 @@ namespace Concurrency {
template <typename Performer> class AsyncUpdater {
public:
template <typename... Args> AsyncUpdater(Args&&... args) :
performer_(std::forward<Args>(args)...),
performer(std::forward<Args>(args)...),
actions_(std::make_unique<ActionVector>()),
performer_thread_{
[this] {
@ -30,7 +30,7 @@ template <typename Performer> class AsyncUpdater {
while(!should_quit) {
// Wait for new actions to be signalled, and grab them.
std::unique_lock lock(condition_mutex_);
while(!actions_) {
while(actions_->empty()) {
condition_.wait(lock);
}
std::swap(actions, actions_);
@ -38,7 +38,7 @@ template <typename Performer> class AsyncUpdater {
// Update to now.
auto time_now = Time::nanos_now();
performer_.perform(time_now - last_fired);
performer.perform(time_now - last_fired);
last_fired = time_now;
// Perform the actions.
@ -68,10 +68,10 @@ template <typename Performer> class AsyncUpdater {
performer_thread_.join();
}
private:
// The object that will actually receive time advances.
Performer performer_;
Performer performer;
private:
// The list of actions waiting be performed. These will be elided,
// increasing their latency, if the emulation thread falls behind.
using ActionVector = std::vector<std::function<void(void)>>;

View File

@ -15,7 +15,6 @@ class MachineDocument:
NSWindowDelegate,
CSMachineDelegate,
CSScanTargetViewResponderDelegate,
CSAudioQueueDelegate,
CSROMReciverViewDelegate
{
// MARK: - Mutual Exclusion.
@ -274,17 +273,12 @@ class MachineDocument:
if self.audioQueue == nil || self.audioQueue.samplingRate != selectedSamplingRate || self.audioQueue != self.machine.audioQueue {
self.machine.audioQueue = nil
self.audioQueue = CSAudioQueue(samplingRate: Float64(selectedSamplingRate), isStereo:isStereo)
self.audioQueue.delegate = self
self.machine.audioQueue = self.audioQueue
self.machine.setAudioSamplingRate(Float(selectedSamplingRate), bufferSize:audioQueue.preferredBufferSize, stereo:isStereo)
}
}
}
/// Responds to the CSAudioQueueDelegate dry-queue warning message by requesting a machine update.
final func audioQueueIsRunningDry(_ audioQueue: CSAudioQueue) {
}
// MARK: - Pasteboard Forwarding.
/// Forwards any text currently on the pasteboard into the active machine.

View File

@ -37,9 +37,16 @@
namespace {
struct Updater {};
struct MachineUpdater {
void perform(Time::Nanos duration) {
// Top out at 0.1 seconds; this is a safeguard against a negative
// feedback loop if emulation starts running slowly.
const auto seconds = std::min(Time::seconds(duration), 0.1);
machine->run_for(seconds);
}
Concurrency::AsyncUpdater<Updater> updater();
MachineTypes::TimedMachine *machine = nullptr;
};
}
@ -49,6 +56,10 @@ Concurrency::AsyncUpdater<Updater> updater();
- (void)addLED:(NSString *)led isPersistent:(BOOL)isPersistent;
@end
@interface CSMachine() <CSAudioQueueDelegate>
- (void)audioQueueIsRunningDry:(nonnull CSAudioQueue *)audioQueue;
@end
struct LockProtectedDelegate {
// Contractual promise is: machine, the pointer **and** the object **, may be accessed only
// in sections protected by the machineAccessLock;
@ -106,6 +117,7 @@ struct ActivityObserver: public Activity::Observer {
CSStaticAnalyser *_analyser;
std::unique_ptr<Machine::DynamicMachine> _machine;
MachineTypes::JoystickMachine *_joystickMachine;
Concurrency::AsyncUpdater<MachineUpdater> updater;
CSJoystickManager *_joystickManager;
NSMutableArray<CSMachineLED *> *_leds;
@ -142,6 +154,7 @@ struct ActivityObserver: public Activity::Observer {
[missingROMs appendString:[NSString stringWithUTF8String:wstring_converter.to_bytes(description).c_str()]];
return nil;
}
updater.performer.machine = _machine->timed_machine();
// Use the keyboard as a joystick if the machine has no keyboard, or if it has a 'non-exclusive' keyboard.
_inputMode =
@ -219,6 +232,11 @@ struct ActivityObserver: public Activity::Observer {
}
}
- (void)setAudioQueue:(CSAudioQueue *)audioQueue {
_audioQueue = audioQueue;
audioQueue.delegate = self;
}
- (void)setAudioSamplingRate:(float)samplingRate bufferSize:(NSUInteger)bufferSize stereo:(BOOL)stereo {
@synchronized(self) {
[self setSpeakerDelegate:&_speakerDelegate sampleRate:samplingRate bufferSize:bufferSize stereo:stereo];
@ -442,9 +460,12 @@ struct ActivityObserver: public Activity::Observer {
}
- (void)applyInputEvent:(dispatch_block_t)event {
@synchronized(_inputEvents) {
[_inputEvents addObject:event];
}
updater.update([event] {
event();
});
// @synchronized(_inputEvents) {
// [_inputEvents addObject:event];
// }
}
- (void)clearAllKeys {
@ -655,9 +676,21 @@ struct ActivityObserver: public Activity::Observer {
#pragma mark - Timer
- (void)audioQueueIsRunningDry:(nonnull CSAudioQueue *)audioQueue {
// TODO: Make audio flushes overt, and do one here.
updater.update([] {});
}
- (void)scanTargetViewDisplayLinkDidFire:(CSScanTargetView *)view now:(const CVTimeStamp *)now outputTime:(const CVTimeStamp *)outputTime {
updater.update([self] {
dispatch_async(dispatch_get_main_queue(), ^{
[self.view updateBacking];
[self.view draw];
});
});
// First order of business: grab a timestamp.
const auto timeNow = Time::nanos_now();
/* const auto timeNow = Time::nanos_now();
BOOL isSyncLocking;
@synchronized(self) {
@ -682,13 +715,14 @@ struct ActivityObserver: public Activity::Observer {
// Draw the current output. (TODO: do this within the timer if either raster racing or, at least, sync matching).
if(!isSyncLocking) {
[self.view draw];
}
}*/
}
#define TICKS 1000
#define TICKS 120
- (void)start {
__block auto lastTime = Time::nanos_now();
// updater.performer.machine = _machine->timed_machine();
/* __block auto lastTime = Time::nanos_now();
_timer = [[CSHighPrecisionTimer alloc] initWithTask:^{
// Grab the time now and, therefore, the amount of time since the timer last fired
@ -762,7 +796,7 @@ struct ActivityObserver: public Activity::Observer {
}
lastTime = timeNow;
} interval:uint64_t(1000000000) / uint64_t(TICKS)];
} interval:uint64_t(1000000000) / uint64_t(TICKS)];*/
}
#undef TICKS