From 99a35266e143c227aad92c0f91f53e07f1fecb16 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 19 Feb 2017 21:20:37 -0500 Subject: [PATCH] Attempted to bring frequency-switching logic into the cross-platform realm. Which for now creates an issue with the OpenGL context. --- Machines/Atari2600/Atari2600.cpp | 47 ++++++++++++- Machines/Atari2600/Atari2600.hpp | 17 ++++- Machines/Atari2600/TIA.cpp | 66 +++++++++---------- .../Machine/Wrappers/CSAtari2600.mm | 36 ---------- 4 files changed, 95 insertions(+), 71 deletions(-) diff --git a/Machines/Atari2600/Atari2600.cpp b/Machines/Atari2600/Atari2600.cpp index 64ed2e963..d796fd983 100644 --- a/Machines/Atari2600/Atari2600.cpp +++ b/Machines/Atari2600/Atari2600.cpp @@ -21,7 +21,9 @@ Machine::Machine() : rom_pages_{nullptr, nullptr, nullptr, nullptr}, tia_input_value_{0xff, 0xff}, cycles_since_speaker_update_(0), - cycles_since_video_update_(0) + cycles_since_video_update_(0), + frame_record_pointer_(0), + is_ntsc_(true) { set_clock_rate(NTSC_clock_rate); } @@ -31,6 +33,7 @@ void Machine::setup_output(float aspect_ratio) tia_.reset(new TIA); speaker_.reset(new Speaker); speaker_->set_input_rate((float)(get_clock_rate() / 38.0)); + tia_->get_crt()->set_delegate(this); } void Machine::close_output() @@ -288,3 +291,45 @@ void Machine::synchronise() update_video(); speaker_->flush(); } + +#pragma mark - CRT delegate + +void Machine::crt_did_end_batch_of_frames(Outputs::CRT::CRT *crt, unsigned int number_of_frames, unsigned int number_of_unexpected_vertical_syncs) +{ + frame_records_[frame_record_pointer_].number_of_frames = number_of_frames; + frame_records_[frame_record_pointer_].number_of_unexpected_vertical_syncs = number_of_unexpected_vertical_syncs; + const size_t number_of_frame_records = sizeof(frame_records_) / sizeof(frame_records_[0]); + frame_record_pointer_ = (frame_record_pointer_ + 1) % number_of_frame_records; + + unsigned int total_number_of_frames = 0; + unsigned int total_number_of_unexpected_vertical_syncs = 0; + for(size_t c = 0; c < number_of_frame_records; c++) + { + if(!frame_records_[c].number_of_frames) return; + total_number_of_frames += frame_records_[c].number_of_frames; + total_number_of_unexpected_vertical_syncs += frame_records_[c].number_of_unexpected_vertical_syncs; + } + + if(total_number_of_unexpected_vertical_syncs >= total_number_of_frames >> 1) + { + for(size_t c = 0; c < number_of_frame_records; c++) + { + frame_records_[c].number_of_frames = 0; + frame_records_[c].number_of_unexpected_vertical_syncs = 0; + } + is_ntsc_ ^= true; + + if(is_ntsc_) + { + set_clock_rate(NTSC_clock_rate); + tia_->set_output_mode(TIA::OutputMode::NTSC); + } + else + { + set_clock_rate(PAL_clock_rate); + tia_->set_output_mode(TIA::OutputMode::PAL); + } + + speaker_->set_input_rate((float)(get_clock_rate() / 38.0)); + } +} diff --git a/Machines/Atari2600/Atari2600.hpp b/Machines/Atari2600/Atari2600.hpp index d78bae584..f0970348e 100644 --- a/Machines/Atari2600/Atari2600.hpp +++ b/Machines/Atari2600/Atari2600.hpp @@ -28,7 +28,8 @@ const unsigned int number_of_recorded_counters = 7; class Machine: public CPU6502::Processor, public CRTMachine::Machine, - public ConfigurationTarget::Machine { + public ConfigurationTarget::Machine, + public Outputs::CRT::Delegate { public: Machine(); @@ -51,6 +52,9 @@ class Machine: virtual std::shared_ptr get_speaker() { return speaker_; } virtual void run_for_cycles(int number_of_cycles) { CPU6502::Processor::run_for_cycles(number_of_cycles); } + // to satisfy Outputs::CRT::Delegate + virtual void crt_did_end_batch_of_frames(Outputs::CRT::CRT *crt, unsigned int number_of_frames, unsigned int number_of_unexpected_vertical_syncs); + private: uint8_t *rom_, *rom_pages_[4]; size_t rom_size_; @@ -72,6 +76,17 @@ class Machine: // video backlog accumulation counter unsigned int cycles_since_video_update_; void update_video(); + + // output frame rate tracker + struct FrameRecord + { + unsigned int number_of_frames; + unsigned int number_of_unexpected_vertical_syncs; + + FrameRecord() : number_of_frames(0), number_of_unexpected_vertical_syncs(0) {} + } frame_records_[4]; + unsigned int frame_record_pointer_; + bool is_ntsc_; }; } diff --git a/Machines/Atari2600/TIA.cpp b/Machines/Atari2600/TIA.cpp index fd5ebb3fd..1ba2660b4 100644 --- a/Machines/Atari2600/TIA.cpp +++ b/Machines/Atari2600/TIA.cpp @@ -143,17 +143,40 @@ TIA::TIA(std::function line_end_function) : TIA(fa void TIA::set_output_mode(Atari2600::TIA::OutputMode output_mode) { - // this is the NTSC phase offset function; see below for PAL - crt_->set_composite_sampling_function( - "float composite_sample(usampler2D texID, vec2 coordinate, vec2 iCoordinate, float phase, float amplitude)" - "{" - "uint c = texture(texID, coordinate).r;" - "uint y = c & 14u;" - "uint iPhase = (c >> 4);" + Outputs::CRT::DisplayType display_type; + + if(output_mode == OutputMode::NTSC) + { + crt_->set_composite_sampling_function( + "float composite_sample(usampler2D texID, vec2 coordinate, vec2 iCoordinate, float phase, float amplitude)" + "{" + "uint c = texture(texID, coordinate).r;" + "uint y = c & 14u;" + "uint iPhase = (c >> 4);" + + "float phaseOffset = 6.283185308 * float(iPhase) / 13.0 + 5.074880441076923;" + "return mix(float(y) / 14.0, step(1, iPhase) * cos(phase + phaseOffset), amplitude);" + "}"); + display_type = Outputs::CRT::DisplayType::NTSC60; + } + else + { + crt_->set_composite_sampling_function( + "float composite_sample(usampler2D texID, vec2 coordinate, vec2 iCoordinate, float phase, float amplitude)" + "{" + "uint c = texture(texID, coordinate).r;" + "uint y = c & 14u;" + "uint iPhase = (c >> 4);" + + "uint direction = iPhase & 1u;" + "float phaseOffset = float(7u - direction) + (float(direction) - 0.5) * 2.0 * float(iPhase >> 1);" + "phaseOffset *= 6.283185308 / 12.0;" + "return mix(float(y) / 14.0, step(4, (iPhase + 2u) & 15u) * cos(phase + phaseOffset), amplitude);" + "}"); + display_type = Outputs::CRT::DisplayType::PAL50; + } + crt_->set_new_display_type(cycles_per_line * 2 + 1, display_type); - "float phaseOffset = 6.283185308 * float(iPhase) / 13.0 + 5.074880441076923;" - "return mix(float(y) / 14.0, step(1, iPhase) * cos(phase + phaseOffset), amplitude);" - "}"); /* speaker_->set_input_rate((float)(get_clock_rate() / 38.0));*/ } @@ -161,29 +184,6 @@ TIA::~TIA() { } -/*void Machine::switch_region() -{ - // the PAL function - crt_->set_composite_sampling_function( - "float composite_sample(usampler2D texID, vec2 coordinate, vec2 iCoordinate, float phase, float amplitude)" - "{" - "uint c = texture(texID, coordinate).r;" - "uint y = c & 14u;" - "uint iPhase = (c >> 4);" - - "uint direction = iPhase & 1u;" - "float phaseOffset = float(7u - direction) + (float(direction) - 0.5) * 2.0 * float(iPhase >> 1);" - "phaseOffset *= 6.283185308 / 12.0;" - "return mix(float(y) / 14.0, step(4, (iPhase + 2u) & 15u) * cos(phase + phaseOffset), amplitude);" - "}"); - - crt_->set_new_timing(228, 312, Outputs::CRT::ColourSpace::YUV, 228, 1, true); - - is_pal_region_ = true; - speaker_->set_input_rate((float)(get_clock_rate() / 38.0)); - set_clock_rate(PAL_clock_rate); -}*/ - // justification for +5: "we need to wait at least 71 [clocks] before the HMOVE operation is complete"; // which will take 16*4 + 2 = 66 cycles from the first compare, implying the first compare must be // in five cycles from now diff --git a/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSAtari2600.mm b/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSAtari2600.mm index 099611af8..08c003fbc 100644 --- a/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSAtari2600.mm +++ b/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSAtari2600.mm @@ -11,42 +11,8 @@ #include "Atari2600.hpp" #import "CSMachine+Subclassing.h" -@interface CSAtari2600 () -- (void)crt:(Outputs::CRT::CRT *)crt didEndBatchOfFrames:(unsigned int)numberOfFrames withUnexpectedVerticalSyncs:(unsigned int)numberOfUnexpectedSyncs; -@end - -struct CRTDelegate: public Outputs::CRT::Delegate { - __weak CSAtari2600 *atari2600; - void crt_did_end_batch_of_frames(Outputs::CRT::CRT *crt, unsigned int number_of_frames, unsigned int number_of_unexpected_vertical_syncs) { - [atari2600 crt:crt didEndBatchOfFrames:number_of_frames withUnexpectedVerticalSyncs:number_of_unexpected_vertical_syncs]; - } -}; - @implementation CSAtari2600 { Atari2600::Machine _atari2600; - CRTDelegate _crtDelegate; - - int _frameCount; - int _hitCount; - BOOL _didDecideRegion; - int _batchesReceived; -} - -- (void)crt:(Outputs::CRT::CRT *)crt didEndBatchOfFrames:(unsigned int)numberOfFrames withUnexpectedVerticalSyncs:(unsigned int)numberOfUnexpectedSyncs { - if(!_didDecideRegion) - { - _batchesReceived++; - if(_batchesReceived == 2) - { - _didDecideRegion = YES; - if(numberOfUnexpectedSyncs >= numberOfFrames >> 1) - { - [self.view performWithGLContext:^{ -// _atari2600.switch_region(); - }]; - } - } - } } - (void)setDirection:(CSJoystickDirection)direction onPad:(NSUInteger)pad isPressed:(BOOL)isPressed { @@ -78,8 +44,6 @@ struct CRTDelegate: public Outputs::CRT::Delegate { - (void)setupOutputWithAspectRatio:(float)aspectRatio { @synchronized(self) { [super setupOutputWithAspectRatio:aspectRatio]; - _atari2600.get_crt()->set_delegate(&_crtDelegate); - _crtDelegate.atari2600 = self; } }