From b9aca39eb0086e0e5e0aed07202d000629b9b534 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 22 Nov 2018 22:43:42 -0500 Subject: [PATCH] Reintroduces Vic-20 output. Resolving errors in shader generation while I'm here. --- Components/6560/6560.hpp | 39 ++++++++-------------- Machines/Commodore/Vic-20/Vic20.cpp | 34 ++++++++----------- Outputs/OpenGL/ScanTargetGLSLFragments.cpp | 11 ++++-- Outputs/ScanTarget.hpp | 4 +-- 4 files changed, 37 insertions(+), 51 deletions(-) diff --git a/Components/6560/6560.hpp b/Components/6560/6560.hpp index 3783247e2..1c4c3f714 100644 --- a/Components/6560/6560.hpp +++ b/Components/6560/6560.hpp @@ -64,23 +64,12 @@ 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_(65*4, 4, Outputs::Display::Type::NTSC60, Outputs::Display::InputDataType::Luminance8Phase8), audio_generator_(audio_queue_), speaker_(audio_generator_) { -// crt_->set_svideo_sampling_function( -// "vec2 svideo_sample(usampler2D texID, vec2 coordinate, float phase, float amplitude)" -// "{" -// "vec2 yc = texture(texID, coordinate).rg / vec2(255.0);" -// -// "float phaseOffset = 6.283185308 * 2.0 * yc.y;" -// "float chroma = step(yc.y, 0.75) * cos(phase + phaseOffset);" -// -// "return vec2(yc.x, chroma);" -// "}"); - // default to s-video output -// crt_->set_video_signal(Outputs::Display::VideoSignal::SVideo); +// crt_.set_video_signal(Outputs::Display::VideoSignal::SVideo); // default to NTSC set_output_mode(OutputMode::NTSC); @@ -94,7 +83,7 @@ template class MOS6560 { speaker_.set_input_rate(static_cast(clock_rate / 4.0)); } - Outputs::CRT::CRT *get_crt() { return crt_.get(); } + void set_scan_target(Outputs::Display::ScanTarget *scan_target) { crt_.set_scan_target(scan_target); } Outputs::Speaker::Speaker *get_speaker() { return &speaker_; } void set_high_frequency_cutoff(float cutoff) { @@ -155,14 +144,14 @@ template class MOS6560 { break; } - crt_->set_new_display_type(timing_.cycles_per_line*4, display_type); + crt_.set_new_display_type(timing_.cycles_per_line*4, display_type); switch(output_mode) { case OutputMode::PAL: - crt_->set_visible_area(Outputs::Display::Rect(0.1f, 0.07f, 0.9f, 0.9f)); + crt_.set_visible_area(Outputs::Display::Rect(0.1f, 0.07f, 0.9f, 0.9f)); break; case OutputMode::NTSC: - crt_->set_visible_area(Outputs::Display::Rect(0.05f, 0.05f, 0.9f, 0.9f)); + crt_.set_visible_area(Outputs::Display::Rect(0.05f, 0.05f, 0.9f, 0.9f)); break; } @@ -284,17 +273,17 @@ template class MOS6560 { // update the CRT if(this_state_ != output_state_) { switch(output_state_) { - case State::Sync: crt_->output_sync(cycles_in_state_ * 4); break; - case State::ColourBurst: crt_->output_colour_burst(cycles_in_state_ * 4, (is_odd_frame_ || is_odd_line_) ? 128 : 0); break; - case State::Border: output_border(cycles_in_state_ * 4); break; - case State::Pixels: crt_->output_data(cycles_in_state_ * 4); break; + case State::Sync: crt_.output_sync(cycles_in_state_ * 4); break; + case State::ColourBurst: crt_.output_colour_burst(cycles_in_state_ * 4, (is_odd_frame_ || is_odd_line_) ? 128 : 0); break; + case State::Border: output_border(cycles_in_state_ * 4); break; + case State::Pixels: crt_.output_data(cycles_in_state_ * 4); break; } output_state_ = this_state_; cycles_in_state_ = 0; pixel_pointer = nullptr; if(output_state_ == State::Pixels) { - pixel_pointer = reinterpret_cast(crt_->begin_data(260)); + pixel_pointer = reinterpret_cast(crt_.begin_data(260)); } } cycles_in_state_++; @@ -438,7 +427,7 @@ template class MOS6560 { private: BusHandler &bus_handler_; - std::unique_ptr crt_; + Outputs::CRT::CRT crt_; Concurrency::DeferringAsyncTaskQueue audio_queue_; AudioGenerator audio_generator_; @@ -512,9 +501,9 @@ template class MOS6560 { uint16_t *pixel_pointer; void output_border(int number_of_cycles) { - uint16_t *colour_pointer = reinterpret_cast(crt_->begin_data(1)); + uint16_t *colour_pointer = reinterpret_cast(crt_.begin_data(1)); if(colour_pointer) *colour_pointer = registers_.borderColour; - crt_->output_level(number_of_cycles); + crt_.output_level(number_of_cycles); } struct { diff --git a/Machines/Commodore/Vic-20/Vic20.cpp b/Machines/Commodore/Vic-20/Vic20.cpp index dd4a73732..302f9f9e0 100644 --- a/Machines/Commodore/Vic-20/Vic20.cpp +++ b/Machines/Commodore/Vic-20/Vic20.cpp @@ -294,6 +294,7 @@ class ConcreteMachine: public: ConcreteMachine(const Analyser::Static::Commodore::Target &target, const ROMMachine::ROMFetcher &rom_fetcher) : m6502_(*this), + mos6560_(mos6560_bus_handler_), user_port_via_port_handler_(new UserPortVIA), keyboard_via_port_handler_(new KeyboardVIA), serial_port_(new SerialPort), @@ -377,13 +378,16 @@ class ConcreteMachine: if(target.region == Analyser::Static::Commodore::Target::Region::American || target.region == Analyser::Static::Commodore::Target::Region::Japanese) { // NTSC set_clock_rate(1022727); - output_mode_ = MOS::MOS6560::OutputMode::NTSC; + mos6560_.set_output_mode(MOS::MOS6560::OutputMode::NTSC); } else { // PAL set_clock_rate(1108404); - output_mode_ = MOS::MOS6560::OutputMode::PAL; + mos6560_.set_output_mode(MOS::MOS6560::OutputMode::PAL); } + mos6560_.set_high_frequency_cutoff(1600); // There is a 1.6Khz low-pass filter in the Vic-20. + mos6560_.set_clock_rate(get_clock_rate()); + // Initialise the memory maps as all pointing to nothing memset(processor_read_memory_map_, 0, sizeof(processor_read_memory_map_)); memset(processor_write_memory_map_, 0, sizeof(processor_write_memory_map_)); @@ -501,7 +505,7 @@ class ConcreteMachine: if((address&0xfc00) == 0x9000) { if(!(address&0x100)) { update_video(); - result &= mos6560_->get_register(address); + result &= mos6560_.get_register(address); } if(address & 0x10) result &= user_port_via_.get_register(address); if(address & 0x20) result &= keyboard_via_.get_register(address); @@ -588,7 +592,7 @@ class ConcreteMachine: // The VIC is selected by bit 8 = 0 if(!(address&0x100)) { update_video(); - mos6560_->set_register(address, *value); + mos6560_.set_register(address, *value); } // The first VIA is selected by bit 4 = 1. if(address & 0x10) user_port_via_.set_register(address, *value); @@ -613,7 +617,7 @@ class ConcreteMachine: void flush() { update_video(); - mos6560_->flush(); + mos6560_.flush(); } void run_for(const Cycles cycles) override final { @@ -621,22 +625,11 @@ class ConcreteMachine: } void set_scan_target(Outputs::Display::ScanTarget *scan_target) override final { - mos6560_.reset(new MOS::MOS6560::MOS6560(mos6560_bus_handler_)); - mos6560_->set_high_frequency_cutoff(1600); // There is a 1.6Khz low-pass filter in the Vic-20. - mos6560_->set_output_mode(output_mode_); - mos6560_->set_clock_rate(get_clock_rate()); + mos6560_.set_scan_target(scan_target); } -// void close_output() override final { -// mos6560_ = nullptr; -// } -// -// Outputs::CRT::CRT *get_crt() override final { -// return mos6560_->get_crt(); -// } - Outputs::Speaker::Speaker *get_speaker() override final { - return mos6560_->get_speaker(); + return mos6560_.get_speaker(); } void mos6522_did_change_interrupt_status(void *mos6522) override final { @@ -701,7 +694,7 @@ class ConcreteMachine: private: void update_video() { - mos6560_->run_for(cycles_since_mos6560_update_.flush()); + mos6560_.run_for(cycles_since_mos6560_update_.flush()); } CPU::MOS6502::Processor m6502_; @@ -731,8 +724,7 @@ class ConcreteMachine: Cycles cycles_since_mos6560_update_; Vic6560BusHandler mos6560_bus_handler_; - MOS::MOS6560::OutputMode output_mode_; - std::unique_ptr> mos6560_; + MOS::MOS6560::MOS6560 mos6560_; std::shared_ptr user_port_via_port_handler_; std::shared_ptr keyboard_via_port_handler_; std::shared_ptr serial_port_; diff --git a/Outputs/OpenGL/ScanTargetGLSLFragments.cpp b/Outputs/OpenGL/ScanTargetGLSLFragments.cpp index cedf3b24e..e8df086ed 100644 --- a/Outputs/OpenGL/ScanTargetGLSLFragments.cpp +++ b/Outputs/OpenGL/ScanTargetGLSLFragments.cpp @@ -190,9 +190,14 @@ std::unique_ptr ScanTarget::input_shader(InputDataType input_data_type, fragment_shader += "fragColour = vec4(vec3(texture(textureName, textureCoordinate).r / 255.0), 1.0);"; break; - case InputDataType::Phase8Luminance8: + case InputDataType::Luminance8Phase8: computed_display_type = DisplayType::SVideo; - fragment_shader += "fragColour = vec4(texture(textureName, textureCoordinate).rg / vec2(255.0), 0.0, 1.0);"; + fragment_shader += + "vec2 yc = texture(textureName, textureCoordinate).rg / vec2(255.0);" + + "float phaseOffset = 3.141592654 * 2.0 * 2.0 * yc.y;" + "float chroma = step(yc.y, 0.75) * cos(compositeAngle + phaseOffset);" + "fragColour = vec4(yc.x, chroma, 0.0, 1.0);"; break; case InputDataType::Red1Green1Blue1: @@ -233,7 +238,7 @@ std::unique_ptr ScanTarget::input_shader(InputDataType input_data_type, } // If the output type isn't SVideo, add an SVideo to composite step. - if(computed_display_type != DisplayType::SVideo) { + if(display_type != DisplayType::SVideo) { fragment_shader += "fragColour = vec4(vec3(mix(fragColour.r, 2.0*(fragColour.g - 0.5), compositeAmplitudeOut)), 1.0);"; } } diff --git a/Outputs/ScanTarget.hpp b/Outputs/ScanTarget.hpp index c06f3dcf5..75d9ac311 100644 --- a/Outputs/ScanTarget.hpp +++ b/Outputs/ScanTarget.hpp @@ -70,7 +70,7 @@ enum class InputDataType { // of a colour subcarrier. So they can be used to generate a luminance signal, // or an s-video pipeline. - Phase8Luminance8, // 2 bytes/pixel; first is phase, second is luminance. + Luminance8Phase8, // 2 bytes/pixel; first is luminance, second is phase. // Phase is encoded on a 192-unit circle; anything // greater than 192 implies that the colour part of // the signal should be omitted. @@ -92,7 +92,7 @@ inline size_t size_for_data_type(InputDataType data_type) { case InputDataType::Red2Green2Blue2: return 1; - case InputDataType::Phase8Luminance8: + case InputDataType::Luminance8Phase8: case InputDataType::Red4Green4Blue4: return 2;