From f6562de325b81071287a4c886ac3f71c79e847cf Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 3 Nov 2018 23:40:39 -0400 Subject: [PATCH] Possibly adds enough for the Electron and ZX80 to start outputting dummy lines. Let's see! --- Components/6560/6560.hpp | 2 +- Components/9918/9918.cpp | 5 ++- Machines/AmstradCPC/AmstradCPC.cpp | 2 +- Machines/AppleII/Video.cpp | 2 +- Machines/Atari2600/TIA.cpp | 2 +- Machines/Electron/Electron.cpp | 10 +---- Machines/Electron/Video.cpp | 10 ++++- Machines/Electron/Video.hpp | 8 ++-- Machines/Oric/Video.cpp | 2 +- Machines/ZX8081/Video.cpp | 5 ++- Machines/ZX8081/Video.hpp | 2 +- Machines/ZX8081/ZX8081.cpp | 2 +- .../Mac/Clock Signal/Machine/CSMachine.mm | 27 +++++++++++++- Outputs/CRT/CRT.cpp | 34 +++++++++++------ Outputs/CRT/CRT.hpp | 37 ++++++++++--------- Outputs/ScanTarget.hpp | 11 ++---- 16 files changed, 97 insertions(+), 64 deletions(-) diff --git a/Components/6560/6560.hpp b/Components/6560/6560.hpp index 38b082b03..70f5d9886 100644 --- a/Components/6560/6560.hpp +++ b/Components/6560/6560.hpp @@ -64,7 +64,7 @@ template class MOS6560 { public: MOS6560(BusHandler &bus_handler) : bus_handler_(bus_handler), - crt_(new Outputs::CRT::CRT(65*4, 4, Outputs::Display::Type::NTSC60, 2)), +// crt_(new Outputs::CRT::CRT(65*4, 4, Outputs::Display::Type::NTSC60, 2)), audio_generator_(audio_queue_), speaker_(audio_generator_) { diff --git a/Components/9918/9918.cpp b/Components/9918/9918.cpp index d043b1913..40710e0a6 100644 --- a/Components/9918/9918.cpp +++ b/Components/9918/9918.cpp @@ -49,8 +49,9 @@ struct ReverseTable { } Base::Base(Personality p) : - personality_(p), - crt_(new Outputs::CRT::CRT(CRTCyclesPerLine, CRTCyclesDivider, Outputs::Display::Type::NTSC60, 4)) { + personality_(p)//, +// crt_(new Outputs::CRT::CRT(CRTCyclesPerLine, CRTCyclesDivider, Outputs::Display::Type::NTSC60, 4)) + { switch(p) { case TI::TMS::TMS9918A: diff --git a/Machines/AmstradCPC/AmstradCPC.cpp b/Machines/AmstradCPC/AmstradCPC.cpp index db547f6ef..1b4097622 100644 --- a/Machines/AmstradCPC/AmstradCPC.cpp +++ b/Machines/AmstradCPC/AmstradCPC.cpp @@ -326,7 +326,7 @@ class CRTCBusHandler { /// Constructs an appropriate CRT for video output. void setup_output(Outputs::Display::ScanTarget *scan_target) { - crt_.reset(new Outputs::CRT::CRT(1024, 16, Outputs::Display::Type::PAL50, 1)); +// crt_.reset(new Outputs::CRT::CRT(1024, 16, Outputs::Display::Type::PAL50, 1)); // crt_->set_rgb_sampling_function( // "vec3 rgb_sample(usampler2D sampler, vec2 coordinate)" // "{" diff --git a/Machines/AppleII/Video.cpp b/Machines/AppleII/Video.cpp index d7ce90d60..19b7452f4 100644 --- a/Machines/AppleII/Video.cpp +++ b/Machines/AppleII/Video.cpp @@ -11,7 +11,7 @@ using namespace AppleII::Video; VideoBase::VideoBase(bool is_iie, std::function &&target) : - crt_(new Outputs::CRT::CRT(910, 1, Outputs::Display::Type::NTSC60, 1)), +// crt_(new Outputs::CRT::CRT(910, 1, Outputs::Display::Type::NTSC60, 1)), is_iie_(is_iie), deferrer_(std::move(target)) { diff --git a/Machines/Atari2600/TIA.cpp b/Machines/Atari2600/TIA.cpp index d748b482b..0e0ee5ff7 100644 --- a/Machines/Atari2600/TIA.cpp +++ b/Machines/Atari2600/TIA.cpp @@ -24,7 +24,7 @@ namespace { TIA::TIA(bool create_crt) { if(create_crt) { - crt_.reset(new Outputs::CRT::CRT(cycles_per_line * 2 - 1, 1, Outputs::Display::Type::NTSC60, 1)); +// crt_.reset(new Outputs::CRT::CRT(cycles_per_line * 2 - 1, 1, Outputs::Display::Type::NTSC60, 1)); // crt_->set_video_signal(Outputs::Display::VideoSignal::Composite); set_output_mode(OutputMode::NTSC); } diff --git a/Machines/Electron/Electron.cpp b/Machines/Electron/Electron.cpp index 2205212f9..010db7391 100644 --- a/Machines/Electron/Electron.cpp +++ b/Machines/Electron/Electron.cpp @@ -374,17 +374,9 @@ class ConcreteMachine: } void setup_output(Outputs::Display::ScanTarget *scan_target) override final { - video_output_.reset(new VideoOutput(ram_)); + video_output_.reset(new VideoOutput(ram_, scan_target)); } -// void close_output() override final { -// video_output_.reset(); -// } -// -// Outputs::CRT::CRT *get_crt() override final { -// return video_output_->get_crt(); -// } - Outputs::Speaker::Speaker *get_speaker() override final { return &speaker_; } diff --git a/Machines/Electron/Video.cpp b/Machines/Electron/Video.cpp index 178e30094..65feffebb 100644 --- a/Machines/Electron/Video.cpp +++ b/Machines/Electron/Video.cpp @@ -38,12 +38,18 @@ namespace { // MARK: - Lifecycle -VideoOutput::VideoOutput(uint8_t *memory) : ram_(memory) { +VideoOutput::VideoOutput(uint8_t *memory, Outputs::Display::ScanTarget *scan_target) : ram_(memory) { memset(palette_, 0xf, sizeof(palette_)); setup_screen_map(); setup_base_address(); - crt_.reset(new Outputs::CRT::CRT(crt_cycles_per_line, 8, Outputs::Display::Type::PAL50, 1)); + crt_.reset(new Outputs::CRT::CRT( + crt_cycles_per_line, + 1024, + Outputs::Display::Type::PAL50, + Outputs::Display::ScanTarget::Modals::DataType::Red1Green1Blue1, + scan_target)); + // crt_->set_rgb_sampling_function( // "vec3 rgb_sample(usampler2D sampler, vec2 coordinate)" // "{" diff --git a/Machines/Electron/Video.hpp b/Machines/Electron/Video.hpp index d5df17ff0..716c6d808 100644 --- a/Machines/Electron/Video.hpp +++ b/Machines/Electron/Video.hpp @@ -27,10 +27,12 @@ namespace Electron { class VideoOutput { public: /*! - Instantiates a VideoOutput that will read its pixels from @c memory. The pointer supplied - should be to address 0 in the unexpanded Electron's memory map. + Instantiates a VideoOutput that will read its pixels from @c memory and output video + to @c scan_target. + + The pointer supplied should be to address 0 in the unexpanded Electron's memory map. */ - VideoOutput(uint8_t *memory); + VideoOutput(uint8_t *memory, Outputs::Display::ScanTarget *scan_target); /// @returns the CRT to which output is being painted. Outputs::CRT::CRT *get_crt(); diff --git a/Machines/Oric/Video.cpp b/Machines/Oric/Video.cpp index e0963be47..a7c20a92b 100644 --- a/Machines/Oric/Video.cpp +++ b/Machines/Oric/Video.cpp @@ -23,7 +23,7 @@ namespace { VideoOutput::VideoOutput(uint8_t *memory) : ram_(memory), - crt_(new Outputs::CRT::CRT(64*6, 6, Outputs::Display::Type::PAL50, 2)), +// crt_(new Outputs::CRT::CRT(64*6, 6, Outputs::Display::Type::PAL50, 2)), v_sync_start_position_(PAL50VSyncStartPosition), v_sync_end_position_(PAL50VSyncEndPosition), counter_period_(PAL50Period) { // crt_->set_rgb_sampling_function( diff --git a/Machines/ZX8081/Video.cpp b/Machines/ZX8081/Video.cpp index a2b763b61..d16dae1d5 100644 --- a/Machines/ZX8081/Video.cpp +++ b/Machines/ZX8081/Video.cpp @@ -22,8 +22,9 @@ const std::size_t StandardAllocationSize = 320; } -Video::Video() : - crt_(new Outputs::CRT::CRT(207 * 2, 1, Outputs::Display::Type::PAL50, 1)) { +Video::Video(Outputs::Display::ScanTarget *scan_target) : + crt_(new Outputs::CRT::CRT(207 * 2, 414, Outputs::Display::Type::PAL50, Outputs::Display::ScanTarget::Modals::DataType::Luminance1, scan_target)) + { // Set a composite sampling function that assumes two-level input; either a byte is 0, which is black, // or it is non-zero, which is white. diff --git a/Machines/ZX8081/Video.hpp b/Machines/ZX8081/Video.hpp index dac52b361..bc5813582 100644 --- a/Machines/ZX8081/Video.hpp +++ b/Machines/ZX8081/Video.hpp @@ -27,7 +27,7 @@ namespace ZX8081 { class Video { public: /// Constructs an instance of the video feed; a CRT is also created. - Video(); + Video(Outputs::Display::ScanTarget *scan_target); /// @returns The CRT this video feed is feeding. Outputs::CRT::CRT *get_crt(); diff --git a/Machines/ZX8081/ZX8081.cpp b/Machines/ZX8081/ZX8081.cpp index 49b1053f1..cfaa28bc0 100644 --- a/Machines/ZX8081/ZX8081.cpp +++ b/Machines/ZX8081/ZX8081.cpp @@ -311,7 +311,7 @@ template class ConcreteMachine: } void setup_output(Outputs::Display::ScanTarget *scan_target) override final { - video_.reset(new Video); + video_.reset(new Video(scan_target)); } Outputs::Speaker::Speaker *get_speaker() override final { diff --git a/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm b/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm index 497703324..b3b7c7bba 100644 --- a/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm +++ b/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm @@ -29,6 +29,8 @@ #import #include +#include "ScanTarget.hpp" + @interface CSMachine() - (void)speaker:(Outputs::Speaker::Speaker *)speaker didCompleteSamples:(const int16_t *)samples length:(int)length; - (void)speakerDidChangeInputClock:(Outputs::Speaker::Speaker *)speaker; @@ -71,6 +73,27 @@ struct ActivityObserver: public Activity::Observer { __unsafe_unretained CSMachine *machine; }; +class ScanTarget: public Outputs::Display::ScanTarget { + public: + void set_modals(Modals) {} + + Scan *get_scan() { + return &scan_; + } + + uint8_t *allocate_write_area(size_t required_length, size_t required_alignment) { + write_area_.resize(required_length); + return write_area_.data(); + } + + void submit(bool only_if_no_allocation_failures) { + } + + private: + Scan scan_; + std::vector write_area_; +}; + @implementation CSMachine { SpeakerDelegate _speakerDelegate; ActivityObserver _activityObserver; @@ -83,6 +106,8 @@ struct ActivityObserver: public Activity::Observer { CSJoystickManager *_joystickManager; std::bitset<65536> _depressedKeys; NSMutableArray *_leds; + + ScanTarget _scanTarget; } - (instancetype)initWithAnalyser:(CSStaticAnalyser *)result { @@ -231,7 +256,7 @@ struct ActivityObserver: public Activity::Observer { } - (void)setupOutputWithAspectRatio:(float)aspectRatio { -// _machine->crt_machine()->setup_output(aspectRatio); + _machine->crt_machine()->setup_output(&_scanTarget); // Since OS X v10.6, Macs have had a gamma of 2.2. // _machine->crt_machine()->get_crt()->set_output_gamma(2.2f); diff --git a/Outputs/CRT/CRT.cpp b/Outputs/CRT/CRT.cpp index 5ecb4ef1e..61e0067bf 100644 --- a/Outputs/CRT/CRT.cpp +++ b/Outputs/CRT/CRT.cpp @@ -56,12 +56,14 @@ void CRT::set_new_timing(int cycles_per_line, int height_of_display, Outputs::Di vertical_flywheel_.reset(new Flywheel(multiplied_cycles_per_line * height_of_display, scanlinesVerticalRetraceTime * multiplied_cycles_per_line, (multiplied_cycles_per_line * height_of_display) >> 3)); // figure out the divisor necessary to get the horizontal flywheel into a 16-bit range - const int real_clock_scan_period = (multiplied_cycles_per_line * height_of_display) / (time_multiplier_ * common_output_divisor_); - vertical_flywheel_output_divider_ = static_cast(ceilf(real_clock_scan_period / 65536.0f) * (time_multiplier_ * common_output_divisor_)); +// const int real_clock_scan_period = (multiplied_cycles_per_line * height_of_display) / (time_multiplier_); +// vertical_flywheel_output_divider_ = static_cast(ceilf(real_clock_scan_period / 65536.0f) * (time_multiplier_)); // openGL_output_builder_.set_timing(cycles_per_line, multiplied_cycles_per_line, height_of_display, horizontal_flywheel_->get_scan_period(), vertical_flywheel_->get_scan_period(), vertical_flywheel_output_divider_); - // TODO: set scan_target modals. + scan_target_modals_.expected_vertical_lines = height_of_display; + scan_target_modals_.composite_colour_space = colour_space; + scan_target_->set_modals(scan_target_modals_); } void CRT::set_new_display_type(int cycles_per_line, Outputs::Display::Type displayType) { @@ -91,24 +93,30 @@ void CRT::set_input_gamma(float gamma) { // update_gamma(); } -CRT::CRT(int common_output_divisor, int buffer_depth) : - common_output_divisor_(common_output_divisor) {} - CRT::CRT( int cycles_per_line, - int common_output_divisor, + int pixel_clock_least_common_multiple, int height_of_display, Outputs::Display::ColourSpace colour_space, int colour_cycle_numerator, int colour_cycle_denominator, int vertical_sync_half_lines, bool should_alternate, - int buffer_depth) : - CRT(common_output_divisor, buffer_depth) { + Outputs::Display::ScanTarget::Modals::DataType data_type, + Outputs::Display::ScanTarget *scan_target) { + scan_target_ = scan_target; + scan_target_modals_.source_data_type = data_type; + scan_target_modals_.pixel_clock_least_common_multiple = pixel_clock_least_common_multiple; set_new_timing(cycles_per_line, height_of_display, colour_space, colour_cycle_numerator, colour_cycle_denominator, vertical_sync_half_lines, should_alternate); } -CRT::CRT(int cycles_per_line, int common_output_divisor, Outputs::Display::Type displayType, int buffer_depth) : - CRT(common_output_divisor, buffer_depth) { - set_new_display_type(cycles_per_line, displayType); +CRT::CRT( int cycles_per_line, + int pixel_clock_least_common_multiple, + Outputs::Display::Type display_type, + Outputs::Display::ScanTarget::Modals::DataType data_type, + Outputs::Display::ScanTarget *scan_target) { + scan_target_ = scan_target; + scan_target_modals_.source_data_type = data_type; + scan_target_modals_.pixel_clock_least_common_multiple = pixel_clock_least_common_multiple; + set_new_display_type(cycles_per_line, display_type); } // MARK: - Sync loop @@ -193,6 +201,8 @@ void CRT::advance_cycles(int number_of_cycles, bool hsync_requested, bool vsync_ } } } + + scan_target_->submit(); } // MARK: - stream feeding methods diff --git a/Outputs/CRT/CRT.hpp b/Outputs/CRT/CRT.hpp index bd68aa948..1e4ad124a 100644 --- a/Outputs/CRT/CRT.hpp +++ b/Outputs/CRT/CRT.hpp @@ -27,12 +27,9 @@ class Delegate { class CRT { private: - CRT(int common_output_divisor, int buffer_depth); - // the incoming clock lengths will be multiplied by something to give at least 1000 // sample points per line int time_multiplier_ = 1; - const int common_output_divisor_ = 1; // the two flywheels regulating scanning std::unique_ptr horizontal_flywheel_, vertical_flywheel_; @@ -82,6 +79,7 @@ class CRT { int cycles_per_line_ = 1; Outputs::Display::ScanTarget *scan_target_ = nullptr; + Outputs::Display::ScanTarget::Modals scan_target_modals_; public: /*! Constructs the CRT with a specified clock rate, height and colour subcarrier frequency. @@ -91,10 +89,7 @@ class CRT { @param cycles_per_line The clock rate at which this CRT will be driven, specified as the number of cycles expected to take up one whole scanline of the display. - @param common_output_divisor The greatest a priori common divisor of all cycle counts that will be - supplied to @c output_sync, @c output_data, etc; supply 1 if no greater divisor is known. For many - machines output will run at a fixed multiple of the clock rate; knowing this divisor can improve - internal precision. + @param pixel_clock_least_common_multiple TODO. @param height_of_display The number of lines that nominally form one field of the display, rounded up to the next whole integer. @@ -107,22 +102,22 @@ class CRT { @param vertical_sync_half_lines The expected length of vertical synchronisation (equalisation pulses aside), in multiples of half a line. - @param buffer_depth The depth per pixel of source data buffers to create for this machine. Machines - may provide per-clock-cycle data in the depth that they consider convenient, supplying a sampling - function to convert between their data format and either a composite or RGB signal, allowing that - work to be offloaded onto the GPU and allowing the output signal to be sampled at a rate appropriate - to the display size. + @param data_type TODO. + + @param scan_target TODO. @see @c set_rgb_sampling_function , @c set_composite_sampling_function */ CRT(int cycles_per_line, - int common_output_divisor, + int pixel_clock_least_common_multiple, int height_of_display, Outputs::Display::ColourSpace colour_space, - int colour_cycle_numerator, int colour_cycle_denominator, + int colour_cycle_numerator, + int colour_cycle_denominator, int vertical_sync_half_lines, bool should_alternate, - int buffer_depth); + Outputs::Display::ScanTarget::Modals::DataType data_type, + Outputs::Display::ScanTarget *scan_target); /*! Constructs the CRT with the specified clock rate, with the display height and colour subcarrier frequency dictated by a standard display type and with the requested number of @@ -132,9 +127,10 @@ class CRT { looked up by display type. */ CRT(int cycles_per_line, - int common_output_divisor, + int pixel_clock_least_common_multiple, Outputs::Display::Type display_type, - int buffer_depth); + Outputs::Display::ScanTarget::Modals::DataType data_type, + Outputs::Display::ScanTarget *scan_target); /*! Resets the CRT with new timing information. The CRT then continues as though the new timing had been provided at construction. */ @@ -149,7 +145,12 @@ class CRT { /*! Resets the CRT with new timing information derived from a new display type. The CRT then continues as though the new timing had been provided at construction. */ - void set_new_display_type(int cycles_per_line, Outputs::Display::Type display_type); + void set_new_display_type( + int cycles_per_line, + Outputs::Display::Type display_type); + + // TODO. + void set_new_data_type(Outputs::Display::ScanTarget::Modals::DataType data_type); /*! Output at the sync level. diff --git a/Outputs/ScanTarget.hpp b/Outputs/ScanTarget.hpp index 71ac99ca2..a52cc79d6 100644 --- a/Outputs/ScanTarget.hpp +++ b/Outputs/ScanTarget.hpp @@ -34,7 +34,7 @@ struct Rect { float width, height; } size; - Rect() {} + Rect() : origin({0.0f, 0.0f}), size({1.0f, 1.0f}) {} Rect(float x, float y, float width, float height) : origin({x, y}), size({width, height}) {} }; @@ -178,7 +178,7 @@ struct ScanTarget { /// Announces that the owner is finished with the region created by the most recent @c allocate_write_area /// and indicates that its actual final size was @c actual_length. - virtual void reduce_previous_allocation_to(size_t actual_length) = 0; + virtual void reduce_previous_allocation_to(size_t actual_length) {}; /// Announces that all endpoint pairs and write areas obtained since the last @c submit have now been /// populated with appropriate data. @@ -187,15 +187,10 @@ struct ScanTarget { /// as long as it feels is appropriate subject to an @c flush. virtual void submit(bool only_if_no_allocation_failures = true) = 0; - /// Discards all data and endpoints supplied since the last @c submit. This is generally used when - /// failures in either get_endpoing_pair of allocate_write_area mean that proceeding would produce - /// a faulty total output. - virtual void reset() = 0; - /// Announces that any submitted data not yet output should be output now, but needn't block while /// doing so. This generally communicates that processing is now otherwise 'up to date', so no /// further delay should be allowed. - virtual void flush() = 0; +// virtual void flush() = 0; /*