From e9d9ff0da0d4d76177c3326b3ef59c29f1ae3c7f Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 5 Jan 2019 23:09:17 -0500 Subject: [PATCH] Enhances ScanTarget to provide additional timing information. --- .../xcschemes/Clock Signal.xcscheme | 2 +- Outputs/CRT/CRT.cpp | 33 ++++++++++++------- Outputs/CRT/CRT.hpp | 2 ++ Outputs/OpenGL/ScanTarget.cpp | 10 +++--- Outputs/OpenGL/ScanTarget.hpp | 2 +- Outputs/ScanTarget.hpp | 13 ++++++-- 6 files changed, 41 insertions(+), 21 deletions(-) diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme b/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme index 782b17c09..f9049689f 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme +++ b/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme @@ -68,7 +68,7 @@ get_next_event_in_period(hsync_is_requested, cycles_to_run_for, cycles_advanced); } +Outputs::Display::ScanTarget::Scan::EndPoint CRT::end_point(uint16_t data_offset) { + Display::ScanTarget::Scan::EndPoint end_point; + + end_point.x = uint16_t(horizontal_flywheel_->get_current_output_position()); + end_point.y = uint16_t(vertical_flywheel_->get_current_output_position() / vertical_flywheel_output_divider_); + end_point.composite_angle = int16_t((phase_numerator_ << 6) / phase_denominator_) * (is_alernate_line_ ? -1 : 1); + end_point.data_offset = data_offset; + end_point.cycles_since_end_of_horizontal_retrace = uint16_t(cycles_since_horizontal_sync_ / time_multiplier_); + + return end_point; +} + void CRT::advance_cycles(int number_of_cycles, bool hsync_requested, bool vsync_requested, const Scan::Type type, int number_of_samples) { number_of_cycles *= time_multiplier_; @@ -186,16 +198,14 @@ void CRT::advance_cycles(int number_of_cycles, bool hsync_requested, bool vsync_ // If outputting, store the start location and scan constants. if(next_scan) { - next_scan->end_points[0].x = uint16_t(horizontal_flywheel_->get_current_output_position()); - next_scan->end_points[0].y = uint16_t(vertical_flywheel_->get_current_output_position() / vertical_flywheel_output_divider_); - next_scan->end_points[0].composite_angle = int16_t((phase_numerator_ << 6) / phase_denominator_) * (is_alernate_line_ ? -1 : 1); - next_scan->end_points[0].data_offset = uint16_t((total_cycles - number_of_cycles) * number_of_samples / total_cycles); + next_scan->end_points[0] = end_point(uint16_t((total_cycles - number_of_cycles) * number_of_samples / total_cycles)); next_scan->composite_amplitude = colour_burst_amplitude_; } // Advance time: that'll affect both the colour subcarrier position and the number of cycles left to run. phase_numerator_ += next_run_length * colour_cycle_numerator_; number_of_cycles -= next_run_length; + cycles_since_horizontal_sync_ += next_run_length; // React to the incoming event. horizontal_flywheel_->apply_event(next_run_length, (next_run_length == time_until_horizontal_sync_event) ? next_horizontal_sync_event : Flywheel::SyncEvent::None); @@ -203,10 +213,7 @@ void CRT::advance_cycles(int number_of_cycles, bool hsync_requested, bool vsync_ // End the scan if necessary. if(next_scan) { - next_scan->end_points[1].x = uint16_t(horizontal_flywheel_->get_current_output_position()); - next_scan->end_points[1].y = uint16_t(vertical_flywheel_->get_current_output_position() / vertical_flywheel_output_divider_); - next_scan->end_points[1].composite_angle = int16_t((phase_numerator_ << 6) / phase_denominator_) * (is_alernate_line_ ? -1 : 1); - next_scan->end_points[1].data_offset = uint16_t((total_cycles - number_of_cycles) * number_of_samples / total_cycles); + next_scan->end_points[1] = end_point(uint16_t((total_cycles - number_of_cycles) * number_of_samples / total_cycles)); scan_target_->end_scan(); } @@ -217,13 +224,15 @@ void CRT::advance_cycles(int number_of_cycles, bool hsync_requested, bool vsync_ ? Outputs::Display::ScanTarget::Event::BeginHorizontalRetrace : Outputs::Display::ScanTarget::Event::EndHorizontalRetrace; scan_target_->announce( event, - uint16_t(horizontal_flywheel_->get_current_output_position()), - uint16_t(vertical_flywheel_->get_current_output_position() / vertical_flywheel_output_divider_)); + !(horizontal_flywheel_->is_in_retrace() || vertical_flywheel_->is_in_retrace()), + end_point(uint16_t((total_cycles - number_of_cycles) * number_of_samples / total_cycles))); // Prepare for the next line. if(next_horizontal_sync_event == Flywheel::SyncEvent::StartRetrace) { is_alernate_line_ ^= phase_alternates_; colour_burst_amplitude_ = 0; + } else { + cycles_since_horizontal_sync_ = 0; } } @@ -234,8 +243,8 @@ void CRT::advance_cycles(int number_of_cycles, bool hsync_requested, bool vsync_ ? Outputs::Display::ScanTarget::Event::BeginVerticalRetrace : Outputs::Display::ScanTarget::Event::EndVerticalRetrace; scan_target_->announce( event, - uint16_t(horizontal_flywheel_->get_current_output_position()), - uint16_t(vertical_flywheel_->get_current_output_position() / vertical_flywheel_output_divider_)); + !(horizontal_flywheel_->is_in_retrace() || vertical_flywheel_->is_in_retrace()), + end_point(uint16_t((total_cycles - number_of_cycles) * number_of_samples / total_cycles))); } // if this is vertical retrace then adcance a field diff --git a/Outputs/CRT/CRT.hpp b/Outputs/CRT/CRT.hpp index c0ecc6b0d..89b76bd76 100644 --- a/Outputs/CRT/CRT.hpp +++ b/Outputs/CRT/CRT.hpp @@ -41,6 +41,8 @@ class CRT { // posted on to the scan target. std::unique_ptr horizontal_flywheel_, vertical_flywheel_; int vertical_flywheel_output_divider_ = 1; + int cycles_since_horizontal_sync_ = 0; + Display::ScanTarget::Scan::EndPoint end_point(uint16_t data_offset); struct Scan { enum Type { diff --git a/Outputs/OpenGL/ScanTarget.cpp b/Outputs/OpenGL/ScanTarget.cpp index 787b471c5..ce9440dbb 100644 --- a/Outputs/OpenGL/ScanTarget.cpp +++ b/Outputs/OpenGL/ScanTarget.cpp @@ -222,13 +222,13 @@ void ScanTarget::submit() { allocation_has_failed_ = false; } -void ScanTarget::announce(Event event, uint16_t x, uint16_t y) { +void ScanTarget::announce(Event event, bool is_visible, const Outputs::Display::ScanTarget::Scan::EndPoint &location) { switch(event) { default: break; case ScanTarget::Event::BeginHorizontalRetrace: if(active_line_) { - active_line_->end_points[1].x = x; - active_line_->end_points[1].y = y; + active_line_->end_points[1].x = location.x; + active_line_->end_points[1].y = location.y; } break; case ScanTarget::Event::EndHorizontalRetrace: { @@ -257,8 +257,8 @@ void ScanTarget::announce(Event event, uint16_t x, uint16_t y) { } if(active_line_) { - active_line_->end_points[0].x = x; - active_line_->end_points[0].y = y; + active_line_->end_points[0].x = location.x; + active_line_->end_points[0].y = location.y; active_line_->line = write_pointers_.line; } } break; diff --git a/Outputs/OpenGL/ScanTarget.hpp b/Outputs/OpenGL/ScanTarget.hpp index 669239167..db549a2d1 100644 --- a/Outputs/OpenGL/ScanTarget.hpp +++ b/Outputs/OpenGL/ScanTarget.hpp @@ -53,7 +53,7 @@ class ScanTarget: public Outputs::Display::ScanTarget { uint8_t *begin_data(size_t required_length, size_t required_alignment) override; void end_data(size_t actual_length) override; void submit() override; - void announce(Event event, uint16_t x, uint16_t y) override; + void announce(Event event, bool is_visible, const Outputs::Display::ScanTarget::Scan::EndPoint &location) override; // Extends the definition of a Scan to include two extra fields, // relevant to the way that this scan target processes video. diff --git a/Outputs/ScanTarget.hpp b/Outputs/ScanTarget.hpp index 28c4c151e..9443efd3c 100644 --- a/Outputs/ScanTarget.hpp +++ b/Outputs/ScanTarget.hpp @@ -228,6 +228,9 @@ struct ScanTarget { /// /// It will produce undefined behaviour if signs differ on a single scan. int16_t composite_angle; + + /// Gives the number of cycles since the most recent horizontal retrace ended. + uint16_t cycles_since_end_of_horizontal_retrace; } end_points[2]; /// For composite video, dictates the amplitude of the colour subcarrier as a proportion of @@ -284,8 +287,14 @@ struct ScanTarget { EndVerticalRetrace, }; - /// Provides a hint that the named event has occurred. - virtual void announce(Event event, uint16_t x, uint16_t y) {} + /*! + Provides a hint that the named event has occurred. + + @param event The event. + @param is_visible @c true if the output stream is visible immediately after this event; @c false otherwise. + @param location The location of the event. + */ + virtual void announce(Event event, bool is_visible, const Scan::EndPoint &location) {} }; /*!