From cf810d8357f74249394d485981a758110a8e2580 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 10 Aug 2017 14:42:47 -0400 Subject: [PATCH 1/4] Minor: ensure the CRT is set to output as a monitor. --- Machines/AmstradCPC/AmstradCPC.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Machines/AmstradCPC/AmstradCPC.cpp b/Machines/AmstradCPC/AmstradCPC.cpp index 9d7359321..7859fdd58 100644 --- a/Machines/AmstradCPC/AmstradCPC.cpp +++ b/Machines/AmstradCPC/AmstradCPC.cpp @@ -291,6 +291,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::Monitor); } /// Destructs the CRT. From a1e2646301877f5d356dd30b5fddca88aad6bac6 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 10 Aug 2017 14:58:24 -0400 Subject: [PATCH 2/4] Imposed counter size limits. --- Components/6845/CRTC6845.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Components/6845/CRTC6845.hpp b/Components/6845/CRTC6845.hpp index 5a87c649c..419c4dc63 100644 --- a/Components/6845/CRTC6845.hpp +++ b/Components/6845/CRTC6845.hpp @@ -104,7 +104,7 @@ template class CRTC6845 { bus_state_.row_address = 0; bool is_at_end_of_frame = line_counter_ == registers_[4]; - line_counter_++; + line_counter_ = (line_counter_ + 1) & 0x7f; // check for end of visible lines if(line_counter_ == registers_[6]) { @@ -131,7 +131,7 @@ template class CRTC6845 { line_counter_ = 0; } } else { - bus_state_.row_address++; + bus_state_.row_address = (bus_state_.row_address + 1) & 0x1f; } bus_state_.refresh_address = line_address_; } @@ -141,6 +141,7 @@ template class CRTC6845 { } bus_state_.display_enable = character_is_visible_ && line_is_visible_; + bus_state_.refresh_address &= 0x3fff; bus_handler_.perform_bus_cycle(bus_state_); } } From a5593bec79978dc60281e3c2b9f1c901d9923bd5 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 10 Aug 2017 15:00:14 -0400 Subject: [PATCH 3/4] Threw in support for the light-pen trigger. --- Components/6845/CRTC6845.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Components/6845/CRTC6845.hpp b/Components/6845/CRTC6845.hpp index 419c4dc63..1fe909a51 100644 --- a/Components/6845/CRTC6845.hpp +++ b/Components/6845/CRTC6845.hpp @@ -169,6 +169,11 @@ template class CRTC6845 { registers_[selected_register_] = value & masks[selected_register_]; } + void trigger_light_pen() { + registers_[17] = bus_state_.refresh_address & 0xff; + registers_[16] = bus_state_.refresh_address >> 8; + } + private: Personality personality_; T &bus_handler_; From ad8c8166bc7fc79a31c3fa59ecba1de00b6819a9 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 10 Aug 2017 15:17:08 -0400 Subject: [PATCH 4/4] Built in gamma conversion for all machines, assuming an output of 2.8 for PAL, 2.2 for NTSC. --- .../Mac/Clock Signal/Machine/CSMachine.mm | 3 +++ Outputs/CRT/CRT.cpp | 17 +++++++++++++++++ Outputs/CRT/CRT.hpp | 9 +++++++++ Outputs/CRT/Internals/CRTOpenGL.cpp | 5 +++++ Outputs/CRT/Internals/CRTOpenGL.hpp | 7 +++++++ Outputs/CRT/Internals/Shaders/OutputShader.cpp | 7 ++++++- Outputs/CRT/Internals/Shaders/OutputShader.hpp | 2 ++ 7 files changed, 49 insertions(+), 1 deletion(-) diff --git a/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm b/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm index 9fbc7ffbb..a5aaa10ef 100644 --- a/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm +++ b/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm @@ -116,6 +116,9 @@ struct MachineDelegate: CRTMachine::Machine::Delegate { - (void)setupOutputWithAspectRatio:(float)aspectRatio { self.machine->setup_output(aspectRatio); + + // Since OS X v10.6, Macs have had a gamma of 2.2. + self.machine->get_crt()->set_output_gamma(2.2f); } - (void)drawViewForPixelSize:(CGSize)pixelSize onlyIfDirty:(BOOL)onlyIfDirty { diff --git a/Outputs/CRT/CRT.cpp b/Outputs/CRT/CRT.cpp index aed91f634..acd68cbfc 100644 --- a/Outputs/CRT/CRT.cpp +++ b/Outputs/CRT/CRT.cpp @@ -56,10 +56,12 @@ void CRT::set_new_display_type(unsigned int cycles_per_line, DisplayType display switch(displayType) { case DisplayType::PAL50: set_new_timing(cycles_per_line, 312, ColourSpace::YUV, 709379, 2500, 5, true); // i.e. 283.7516; 2.5 lines = vertical sync + set_input_gamma(2.8f); break; case DisplayType::NTSC60: set_new_timing(cycles_per_line, 262, ColourSpace::YIQ, 455, 2, 6, false); // i.e. 227.5, 3 lines = vertical sync + set_input_gamma(2.2f); break; } } @@ -72,6 +74,21 @@ void CRT::set_composite_function_type(CompositeSourceType type, float offset_of_ } } +void CRT::set_input_gamma(float gamma) { + input_gamma_ = gamma; + update_gamma(); +} + +void CRT::set_output_gamma(float gamma) { + output_gamma_ = gamma; + update_gamma(); +} + +void CRT::update_gamma() { + float gamma_ratio = output_gamma_ / input_gamma_; + openGL_output_builder_.set_gamma(gamma_ratio); +} + CRT::CRT(unsigned int common_output_divisor, unsigned int buffer_depth) : is_receiving_sync_(false), common_output_divisor_(common_output_divisor), diff --git a/Outputs/CRT/CRT.hpp b/Outputs/CRT/CRT.hpp index 13e22085b..19d890ec3 100644 --- a/Outputs/CRT/CRT.hpp +++ b/Outputs/CRT/CRT.hpp @@ -97,6 +97,9 @@ class CRT { unsigned int cycles_per_line_; + float input_gamma_, output_gamma_; + void update_gamma(); + public: /*! Constructs the CRT with a specified clock rate, height and colour subcarrier frequency. The requested number of buffers, each with the requested number of bytes per pixel, @@ -238,6 +241,12 @@ class CRT { openGL_output_builder_.draw_frame(output_width, output_height, only_if_dirty); } + /*! Sets the gamma exponent for the simulated screen. */ + void set_input_gamma(float gamma); + + /*! Sets the gamma exponent for the real, tangible screen on which content will be drawn. */ + void set_output_gamma(float gamma); + /*! Tells the CRT that the next call to draw_frame will occur on a different OpenGL context than the previous. diff --git a/Outputs/CRT/Internals/CRTOpenGL.cpp b/Outputs/CRT/Internals/CRTOpenGL.cpp index 81a2d7a55..2568dd2cf 100644 --- a/Outputs/CRT/Internals/CRTOpenGL.cpp +++ b/Outputs/CRT/Internals/CRTOpenGL.cpp @@ -89,6 +89,7 @@ void OpenGLOutputBuilder::draw_frame(unsigned int output_width, unsigned int out set_timing_uniforms(); set_colour_space_uniforms(); + set_gamma(); } if(fence_ != nullptr) { @@ -375,6 +376,10 @@ void OpenGLOutputBuilder::set_colour_space_uniforms() { if(composite_chrominance_filter_shader_program_) composite_chrominance_filter_shader_program_->set_colour_conversion_matrices(fromRGB, toRGB); } +void OpenGLOutputBuilder::set_gamma() { + if(output_shader_program_) output_shader_program_->set_gamma_ratio(gamma_); +} + float OpenGLOutputBuilder::get_composite_output_width() const { return ((float)colour_cycle_numerator_ * 4.0f) / (float)(colour_cycle_denominator_ * IntermediateBufferWidth); } diff --git a/Outputs/CRT/Internals/CRTOpenGL.hpp b/Outputs/CRT/Internals/CRTOpenGL.hpp index 5be73cca9..164e65395 100644 --- a/Outputs/CRT/Internals/CRTOpenGL.hpp +++ b/Outputs/CRT/Internals/CRTOpenGL.hpp @@ -34,6 +34,7 @@ class OpenGLOutputBuilder { unsigned int colour_cycle_numerator_; unsigned int colour_cycle_denominator_; OutputDevice output_device_; + float gamma_; // timing information to allow reasoning about input information unsigned int input_frequency_; @@ -89,6 +90,7 @@ class OpenGLOutputBuilder { void set_timing_uniforms(); void set_colour_space_uniforms(); + void set_gamma(); void establish_OpenGL_state(); void reset_all_OpenGL_state(); @@ -118,6 +120,11 @@ class OpenGLOutputBuilder { visible_area_ = visible_area; } + inline void set_gamma(float gamma) { + gamma_ = gamma; + set_gamma(); + } + inline std::unique_lock get_output_lock() { return std::unique_lock(output_mutex_); } diff --git a/Outputs/CRT/Internals/Shaders/OutputShader.cpp b/Outputs/CRT/Internals/Shaders/OutputShader.cpp index 7435d059a..1c773828a 100644 --- a/Outputs/CRT/Internals/Shaders/OutputShader.cpp +++ b/Outputs/CRT/Internals/Shaders/OutputShader.cpp @@ -74,12 +74,13 @@ std::unique_ptr OutputShader::make_shader(const char *fragment_met "out vec4 fragColour;" "uniform %s texID;" + "uniform float gamma;" "\n%s\n" "void main(void)" "{" - "fragColour = vec4(%s, 0.5);"//*cos(lateralVarying) + "fragColour = vec4(pow(%s, vec3(gamma)), 0.5);"//*cos(lateralVarying) "}", sampler_type, fragment_methods, colour_expression); @@ -116,6 +117,10 @@ void OutputShader::set_timing(unsigned int height_of_display, unsigned int cycle set_uniform("positionConversion", (GLfloat)horizontal_scan_period, (GLfloat)vertical_scan_period / (GLfloat)vertical_period_divider); } +void OutputShader::set_gamma_ratio(float ratio) { + set_uniform("gamma", ratio); +} + void OutputShader::set_input_width_scaler(float input_scaler) { set_uniform("inputScaler", input_scaler); } diff --git a/Outputs/CRT/Internals/Shaders/OutputShader.hpp b/Outputs/CRT/Internals/Shaders/OutputShader.hpp index 0df8143f4..02db19cdb 100644 --- a/Outputs/CRT/Internals/Shaders/OutputShader.hpp +++ b/Outputs/CRT/Internals/Shaders/OutputShader.hpp @@ -63,6 +63,8 @@ public: */ void set_origin_is_double_height(bool is_double_height); + void set_gamma_ratio(float ratio); + /*! Sets the proportion of the input area that should be considered the whole width — 1.0 means use all available space, 0.5 means use half, etc.