From 33281b9d8921126e4cf7bb6f4452f27d9c71f064 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 30 Mar 2018 10:25:41 -0400 Subject: [PATCH] Introduces S-Video as a video signal type at the interface level. --- Components/9918/9918.cpp | 2 +- Machines/AmstradCPC/AmstradCPC.cpp | 2 +- Machines/Atari2600/TIA.cpp | 2 +- Machines/ColecoVision/ColecoVision.cpp | 2 +- Machines/Electron/Electron.cpp | 2 +- Machines/MSX/MSX.cpp | 2 +- Machines/Oric/Oric.cpp | 6 +++--- Machines/Oric/Video.cpp | 10 +++++----- Machines/Oric/Video.hpp | 4 ++-- Outputs/CRT/CRT.hpp | 27 +++++++++++++++++++++----- Outputs/CRT/CRTTypes.hpp | 7 ++++--- Outputs/CRT/Internals/CRTOpenGL.cpp | 8 ++++---- Outputs/CRT/Internals/CRTOpenGL.hpp | 17 +++++++++------- 13 files changed, 56 insertions(+), 35 deletions(-) diff --git a/Components/9918/9918.cpp b/Components/9918/9918.cpp index e99a4dcaa..f6ba07db1 100644 --- a/Components/9918/9918.cpp +++ b/Components/9918/9918.cpp @@ -96,7 +96,7 @@ TMS9918::TMS9918(Personality p) { "{" "return texture(sampler, coordinate).rgb / vec3(255.0);" "}"); - crt_->set_output_device(Outputs::CRT::OutputDevice::Monitor); + crt_->set_video_signal(Outputs::CRT::VideoSignal::RGB); crt_->set_visible_area(Outputs::CRT::Rect(0.055f, 0.025f, 0.9f, 0.9f)); crt_->set_input_gamma(2.8f); diff --git a/Machines/AmstradCPC/AmstradCPC.cpp b/Machines/AmstradCPC/AmstradCPC.cpp index 8a55b8675..202d06628 100644 --- a/Machines/AmstradCPC/AmstradCPC.cpp +++ b/Machines/AmstradCPC/AmstradCPC.cpp @@ -317,7 +317,7 @@ class CRTCBusHandler { "return vec3(float((sample >> 4) & 3u), float((sample >> 2) & 3u), float(sample & 3u)) / 2.0;" "}"); crt_->set_visible_area(Outputs::CRT::Rect(0.075f, 0.05f, 0.9f, 0.9f)); - crt_->set_output_device(Outputs::CRT::OutputDevice::Monitor); + crt_->set_video_signal(Outputs::CRT::VideoSignal::RGB); } /// Destructs the CRT. diff --git a/Machines/Atari2600/TIA.cpp b/Machines/Atari2600/TIA.cpp index 7f6a8146d..63d637bf6 100644 --- a/Machines/Atari2600/TIA.cpp +++ b/Machines/Atari2600/TIA.cpp @@ -25,7 +25,7 @@ namespace { TIA::TIA(bool create_crt) { if(create_crt) { crt_.reset(new Outputs::CRT::CRT(cycles_per_line * 2 - 1, 1, Outputs::CRT::DisplayType::NTSC60, 1)); - crt_->set_output_device(Outputs::CRT::OutputDevice::Television); + crt_->set_video_signal(Outputs::CRT::VideoSignal::Composite); set_output_mode(OutputMode::NTSC); } diff --git a/Machines/ColecoVision/ColecoVision.cpp b/Machines/ColecoVision/ColecoVision.cpp index 7acd6ca22..67915f5d9 100644 --- a/Machines/ColecoVision/ColecoVision.cpp +++ b/Machines/ColecoVision/ColecoVision.cpp @@ -135,7 +135,7 @@ class ConcreteMachine: void setup_output(float aspect_ratio) override { vdp_.reset(new TI::TMS9918(TI::TMS9918::TMS9918A)); - get_crt()->set_output_device(Outputs::CRT::OutputDevice::Television); + get_crt()->set_video_signal(Outputs::CRT::VideoSignal::Composite); } void close_output() override { diff --git a/Machines/Electron/Electron.cpp b/Machines/Electron/Electron.cpp index edfaaf200..746a65124 100644 --- a/Machines/Electron/Electron.cpp +++ b/Machines/Electron/Electron.cpp @@ -454,7 +454,7 @@ class ConcreteMachine: Configurable::Display display; if(Configurable::get_display(selections_by_option, display)) { - get_crt()->set_output_device((display == Configurable::Display::RGB) ? Outputs::CRT::OutputDevice::Monitor : Outputs::CRT::OutputDevice::Television); + get_crt()->set_video_signal((display == Configurable::Display::RGB) ? Outputs::CRT::VideoSignal::RGB : Outputs::CRT::VideoSignal::Composite); } } diff --git a/Machines/MSX/MSX.cpp b/Machines/MSX/MSX.cpp index aaaa32cc4..faecdcffd 100644 --- a/Machines/MSX/MSX.cpp +++ b/Machines/MSX/MSX.cpp @@ -562,7 +562,7 @@ class ConcreteMachine: Configurable::Display display; if(Configurable::get_display(selections_by_option, display)) { - get_crt()->set_output_device((display == Configurable::Display::RGB) ? Outputs::CRT::OutputDevice::Monitor : Outputs::CRT::OutputDevice::Television); + get_crt()->set_video_signal((display == Configurable::Display::RGB) ? Outputs::CRT::VideoSignal::RGB : Outputs::CRT::VideoSignal::Composite); } } diff --git a/Machines/Oric/Oric.cpp b/Machines/Oric/Oric.cpp index 64e8e1246..4dbec895b 100644 --- a/Machines/Oric/Oric.cpp +++ b/Machines/Oric/Oric.cpp @@ -263,7 +263,7 @@ class ConcreteMachine: use_fast_tape_hack_ = activate; } - void set_output_device(Outputs::CRT::OutputDevice output_device) { + void set_output_device(Outputs::CRT::VideoSignal output_device) { video_output_->set_output_device(output_device); } @@ -392,7 +392,7 @@ class ConcreteMachine: video_output_.reset(new VideoOutput(ram_)); if(!colour_rom_.empty()) video_output_->set_colour_rom(colour_rom_); - set_output_device(Outputs::CRT::OutputDevice::Monitor); + set_output_device(Outputs::CRT::VideoSignal::RGB); } void close_output() override final { @@ -465,7 +465,7 @@ class ConcreteMachine: Configurable::Display display; if(Configurable::get_display(selections_by_option, display)) { - set_output_device((display == Configurable::Display::RGB) ? Outputs::CRT::OutputDevice::Monitor : Outputs::CRT::OutputDevice::Television); + set_output_device((display == Configurable::Display::RGB) ? Outputs::CRT::VideoSignal::RGB : Outputs::CRT::VideoSignal::Composite); } } diff --git a/Machines/Oric/Video.cpp b/Machines/Oric/Video.cpp index 9aff00933..fd8b34851 100644 --- a/Machines/Oric/Video.cpp +++ b/Machines/Oric/Video.cpp @@ -41,13 +41,13 @@ VideoOutput::VideoOutput(uint8_t *memory) : ); crt_->set_composite_function_type(Outputs::CRT::CRT::CompositeSourceType::DiscreteFourSamplesPerCycle, 0.0f); - set_output_device(Outputs::CRT::OutputDevice::Television); + set_output_device(Outputs::CRT::VideoSignal::Composite); crt_->set_visible_area(crt_->get_rect_for_area(53, 224, 16 * 6, 40 * 6, 4.0f / 3.0f)); } -void VideoOutput::set_output_device(Outputs::CRT::OutputDevice output_device) { +void VideoOutput::set_output_device(Outputs::CRT::VideoSignal output_device) { output_device_ = output_device; - crt_->set_output_device(output_device); + crt_->set_video_signal(output_device); } void VideoOutput::set_colour_rom(const std::vector &rom) { @@ -129,7 +129,7 @@ void VideoOutput::run_for(const Cycles cycles) { if(control_byte & 0x60) { if(pixel_target_) { uint16_t colours[2]; - if(output_device_ == Outputs::CRT::OutputDevice::Monitor) { + if(output_device_ == Outputs::CRT::VideoSignal::RGB) { colours[0] = static_cast(paper_ ^ inverse_mask); colours[1] = static_cast(ink_ ^ inverse_mask); } else { @@ -183,7 +183,7 @@ void VideoOutput::run_for(const Cycles cycles) { pixel_target_[0] = pixel_target_[1] = pixel_target_[2] = pixel_target_[3] = pixel_target_[4] = pixel_target_[5] = - (output_device_ == Outputs::CRT::OutputDevice::Monitor) ? paper_ ^ inverse_mask : colour_forms_[paper_ ^ inverse_mask]; + (output_device_ == Outputs::CRT::VideoSignal::RGB) ? paper_ ^ inverse_mask : colour_forms_[paper_ ^ inverse_mask]; } } if(pixel_target_) pixel_target_ += 6; diff --git a/Machines/Oric/Video.hpp b/Machines/Oric/Video.hpp index fe0ff2f38..c3b58436e 100644 --- a/Machines/Oric/Video.hpp +++ b/Machines/Oric/Video.hpp @@ -20,7 +20,7 @@ class VideoOutput { Outputs::CRT::CRT *get_crt(); void run_for(const Cycles cycles); void set_colour_rom(const std::vector &rom); - void set_output_device(Outputs::CRT::OutputDevice output_device); + void set_output_device(Outputs::CRT::VideoSignal output_device); private: uint8_t *ram_; @@ -33,7 +33,7 @@ class VideoOutput { // Output target and device uint16_t *pixel_target_; uint16_t colour_forms_[8]; - Outputs::CRT::OutputDevice output_device_; + Outputs::CRT::VideoSignal output_device_; // Registers uint8_t ink_, paper_; diff --git a/Outputs/CRT/CRT.hpp b/Outputs/CRT/CRT.hpp index 90367a174..be156e071 100644 --- a/Outputs/CRT/CRT.hpp +++ b/Outputs/CRT/CRT.hpp @@ -306,10 +306,27 @@ class CRT { */ void set_composite_function_type(CompositeSourceType type, float offset_of_first_sample = 0.0f); + /*! Sets a function that will map from whatever data the machine provided to an s-video signal. + + If the output mode is composite then a default mapping from RGB to the display's + output mode will be applied. + + @param shader A GLSL fragment including a function with the signature + `vec2 svideo_sample(usampler2D texID, vec2 coordinate, vec2 iCoordinate, float phase)` + that evaluates to the s-video signal level, luminance as the first component and chrominance + as the second, as a function of a source buffer, sampling location and colour + carrier phase. + */ + inline void set_svideo_sampling_function(const std::string &shader) { + enqueue_openGL_function([shader, this] { + openGL_output_builder_.set_svideo_sampling_function(shader); + }); + } + /*! Sets a function that will map from whatever data the machine provided to an RGB signal. - If the output mode is composite then a default mapping from RGB to the display's composite - format will be applied. + If the output mode is composite or svideo then a default mapping from RGB to the display's + output mode will be applied. @param shader A GLSL fragent including a function with the signature `vec3 rgb_sample(usampler2D sampler, vec2 coordinate, vec2 icoordinate)` that evaluates to an RGB colour @@ -329,9 +346,9 @@ class CRT { openGL_output_builder_.texture_builder.set_bookender(std::move(bookender)); } - inline void set_output_device(OutputDevice output_device) { - enqueue_openGL_function([output_device, this] { - openGL_output_builder_.set_output_device(output_device); + inline void set_video_signal(VideoSignal video_signal) { + enqueue_openGL_function([video_signal, this] { + openGL_output_builder_.set_video_signal(video_signal); }); } diff --git a/Outputs/CRT/CRTTypes.hpp b/Outputs/CRT/CRTTypes.hpp index d86cd72a2..66edccfc4 100644 --- a/Outputs/CRT/CRTTypes.hpp +++ b/Outputs/CRT/CRTTypes.hpp @@ -36,9 +36,10 @@ enum class ColourSpace { YUV }; -enum class OutputDevice { - Monitor, - Television +enum class VideoSignal { + RGB, + SVideo, + Composite }; } diff --git a/Outputs/CRT/Internals/CRTOpenGL.cpp b/Outputs/CRT/Internals/CRTOpenGL.cpp index 9bd1b7184..818814076 100644 --- a/Outputs/CRT/Internals/CRTOpenGL.cpp +++ b/Outputs/CRT/Internals/CRTOpenGL.cpp @@ -72,7 +72,7 @@ OpenGLOutputBuilder::~OpenGLOutputBuilder() { } bool OpenGLOutputBuilder::get_is_television_output() { - return output_device_ == OutputDevice::Television || !rgb_input_shader_program_; + return video_signal_ == VideoSignal::Composite || !rgb_input_shader_program_; } void OpenGLOutputBuilder::set_target_framebuffer(GLint target_framebuffer) { @@ -363,9 +363,9 @@ void OpenGLOutputBuilder::prepare_output_vertex_array() { // MARK: - Public Configuration -void OpenGLOutputBuilder::set_output_device(OutputDevice output_device) { - if(output_device_ != output_device) { - output_device_ = output_device; +void OpenGLOutputBuilder::set_video_signal(VideoSignal video_signal) { + if(video_signal_ != video_signal) { + video_signal_ = video_signal; composite_src_output_y_ = 0; last_output_width_ = 0; last_output_height_ = 0; diff --git a/Outputs/CRT/Internals/CRTOpenGL.hpp b/Outputs/CRT/Internals/CRTOpenGL.hpp index 36deb7eb4..6b32f1a5c 100644 --- a/Outputs/CRT/Internals/CRTOpenGL.hpp +++ b/Outputs/CRT/Internals/CRTOpenGL.hpp @@ -33,7 +33,7 @@ class OpenGLOutputBuilder { ColourSpace colour_space_; unsigned int colour_cycle_numerator_; unsigned int colour_cycle_denominator_; - OutputDevice output_device_; + VideoSignal video_signal_; float gamma_; // timing information to allow reasoning about input information @@ -73,6 +73,8 @@ class OpenGLOutputBuilder { std::unique_ptr composite_separation_filter_program_; std::unique_ptr composite_chrominance_filter_shader_program_; + std::unique_ptr svideo_input_shader_program_; + std::unique_ptr rgb_input_shader_program_; std::unique_ptr rgb_filter_shader_program_; @@ -130,8 +132,8 @@ class OpenGLOutputBuilder { return std::unique_lock(output_mutex_); } - inline OutputDevice get_output_device() { - return output_device_; + inline VideoSignal get_output_device() { + return video_signal_; } inline uint16_t get_composite_output_y() { @@ -147,12 +149,13 @@ class OpenGLOutputBuilder { composite_src_output_y_++; } - void set_target_framebuffer(GLint target_framebuffer); + void set_target_framebuffer(GLint); void draw_frame(unsigned int output_width, unsigned int output_height, bool only_if_dirty); void set_openGL_context_will_change(bool should_delete_resources); - void set_composite_sampling_function(const std::string &shader); - void set_rgb_sampling_function(const std::string &shader); - void set_output_device(OutputDevice output_device); + void set_composite_sampling_function(const std::string &); + void set_svideo_sampling_function(const std::string &); + void set_rgb_sampling_function(const std::string &); + void set_video_signal(VideoSignal); void set_timing(unsigned int input_frequency, unsigned int cycles_per_line, unsigned int height_of_display, unsigned int horizontal_scan_period, unsigned int vertical_scan_period, unsigned int vertical_period_divider); };