From 15d17c12d586db943d7e25618f9539236c38c959 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 9 May 2017 21:22:01 -0400 Subject: [PATCH 1/7] Switched the 6560 to two bytes per pixel, since one isn't sufficient for precision and because mixing up the implementation might help me to figure out what's amiss. --- Components/6560/6560.hpp | 44 +++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/Components/6560/6560.hpp b/Components/6560/6560.hpp index cd786888c..444a0dcb2 100644 --- a/Components/6560/6560.hpp +++ b/Components/6560/6560.hpp @@ -43,7 +43,7 @@ class Speaker: public ::Outputs::Filter { template class MOS6560 { public: MOS6560() : - crt_(new Outputs::CRT::CRT(65*4, 4, Outputs::CRT::NTSC60, 1)), + crt_(new Outputs::CRT::CRT(65*4, 4, Outputs::CRT::NTSC60, 2)), speaker_(new Speaker), horizontal_counter_(0), vertical_counter_(0), @@ -53,13 +53,11 @@ template class MOS6560 { crt_->set_composite_sampling_function( "float composite_sample(usampler2D texID, vec2 coordinate, vec2 iCoordinate, float phase, float amplitude)" "{" - "uint c = texture(texID, coordinate).r;" - "float y = float(c >> 4) / 4.0;" - "uint yC = c & 15u;" - "float phaseOffset = 6.283185308 * float(yC) / 16.0;" + "vec2 yc = texture(texID, coordinate).rg / vec2(255.0);" + "float phaseOffset = 6.283185308 * float(yc.y);" "float chroma = cos(phase + phaseOffset);" - "return mix(y, step(yC, 14) * chroma, amplitude);" + "return mix(yc.x, chroma, amplitude);" "}"); // default to NTSC @@ -82,11 +80,13 @@ template class MOS6560 { */ void set_output_mode(OutputMode output_mode) { output_mode_ = output_mode; - const uint8_t luminances[16] = { // range is 0–4 - 0, 4, 1, 3, 2, 2, 1, 3, - 2, 1, 2, 1, 2, 3, 2, 3 + const uint8_t luminances[16] = { + 0, 255, 91, 190, + 134, 176, 84, 224, + 140, 212, 200, 213, + 205, 200, 163, 221 }; - const uint8_t pal_chrominances[16] = { // range is 0–15; 15 is a special case meaning "no chrominance" + const uint8_t pal_chrominances[16] = { 15, 15, 5, 13, 2, 10, 0, 8, 6, 7, 5, 13, 2, 10, 0, 8, }; @@ -118,7 +118,7 @@ template class MOS6560 { } crt_->set_new_display_type((unsigned int)(timing_.cycles_per_line*4), display_type); -// crt_->set_visible_area(Outputs::CRT::Rect(0.1f, 0.1f, 0.8f, 0.8f)); + crt_->set_visible_area(Outputs::CRT::Rect(0.05f, 0.05f, 0.9f, 0.9f)); // switch(output_mode) { // case OutputMode::PAL: @@ -130,7 +130,9 @@ template class MOS6560 { // } for(int c = 0; c < 16; c++) { - colours_[c] = (uint8_t)((luminances[c] << 4) | chrominances[c]); + uint8_t *colour = (uint8_t *)&colours_[c]; + colour[0] = luminances[c]; + colour[1] = chrominances[c] * 15; } } @@ -256,7 +258,7 @@ template class MOS6560 { pixel_pointer = nullptr; if(output_state_ == State::Pixels) { - pixel_pointer = crt_->allocate_write_area(260); + pixel_pointer = (uint16_t *)crt_->allocate_write_area(260); } } cycles_in_state_++; @@ -266,9 +268,9 @@ template class MOS6560 { character_value_ = pixel_data; if(pixel_pointer) { - uint8_t cell_colour = colours_[character_colour_ & 0x7]; + uint16_t cell_colour = colours_[character_colour_ & 0x7]; if(!(character_colour_&0x8)) { - uint8_t colours[2]; + uint16_t colours[2]; if(registers_.invertedCells) { colours[0] = cell_colour; colours[1] = registers_.backgroundColour; @@ -285,7 +287,7 @@ template class MOS6560 { pixel_pointer[6] = colours[(character_value_ >> 1)&1]; pixel_pointer[7] = colours[(character_value_ >> 0)&1]; } else { - uint8_t colours[4] = {registers_.backgroundColour, registers_.borderColour, cell_colour, registers_.auxiliary_colour}; + uint16_t colours[4] = {registers_.backgroundColour, registers_.borderColour, cell_colour, registers_.auxiliary_colour}; pixel_pointer[0] = pixel_pointer[1] = colours[(character_value_ >> 6)&3]; pixel_pointer[2] = @@ -358,7 +360,7 @@ template class MOS6560 { break; case 0xf: { - uint8_t new_border_colour = colours_[value & 0x07]; + uint16_t new_border_colour = colours_[value & 0x07]; if(this_state_ == State::Border && new_border_colour != registers_.borderColour) { output_border(cycles_in_state_ * 4); cycles_in_state_ = 0; @@ -405,7 +407,7 @@ template class MOS6560 { uint8_t first_column_location, first_row_location; uint8_t number_of_columns, number_of_rows; uint16_t character_cell_start_address, video_matrix_start_address; - uint8_t backgroundColour, borderColour, auxiliary_colour; + uint16_t backgroundColour, borderColour, auxiliary_colour; bool invertedCells; uint8_t direct_values[16]; @@ -436,11 +438,11 @@ template class MOS6560 { bool is_odd_frame_, is_odd_line_; // lookup table from 6560 colour index to appropriate PAL/NTSC value - uint8_t colours_[16]; + uint16_t colours_[16]; - uint8_t *pixel_pointer; + uint16_t *pixel_pointer; void output_border(unsigned int number_of_cycles) { - uint8_t *colour_pointer = crt_->allocate_write_area(1); + uint16_t *colour_pointer = (uint16_t *)crt_->allocate_write_area(1); if(colour_pointer) *colour_pointer = registers_.borderColour; crt_->output_level(number_of_cycles); } From b14c8927403b98ef9037fa62415dcbdc3b3cc492 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 10 May 2017 21:29:39 -0400 Subject: [PATCH 2/7] Switched to a safer RAII approach to this lock. --- Outputs/CRT/Internals/CRTOpenGL.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Outputs/CRT/Internals/CRTOpenGL.cpp b/Outputs/CRT/Internals/CRTOpenGL.cpp index 28ec3d0e3..0b5c3f275 100644 --- a/Outputs/CRT/Internals/CRTOpenGL.cpp +++ b/Outputs/CRT/Internals/CRTOpenGL.cpp @@ -336,7 +336,7 @@ void OpenGLOutputBuilder::set_output_device(OutputDevice output_device) { } void OpenGLOutputBuilder::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) { - output_mutex_.lock(); + std::lock_guard lock_guard(output_mutex_); input_frequency_ = input_frequency; cycles_per_line_ = cycles_per_line; height_of_display_ = height_of_display; @@ -345,7 +345,6 @@ void OpenGLOutputBuilder::set_timing(unsigned int input_frequency, unsigned int vertical_period_divider_ = vertical_period_divider; set_timing_uniforms(); - output_mutex_.unlock(); } #pragma mark - Internal Configuration From a34033122991849ce818a586d7f2c55c78e5f234 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 11 May 2017 21:31:58 -0400 Subject: [PATCH 3/7] Introduced 1-bit of saturation, returning black and white as black and white. --- Components/6560/6560.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Components/6560/6560.hpp b/Components/6560/6560.hpp index 444a0dcb2..fccf4e053 100644 --- a/Components/6560/6560.hpp +++ b/Components/6560/6560.hpp @@ -54,10 +54,10 @@ template class MOS6560 { "float composite_sample(usampler2D texID, vec2 coordinate, vec2 iCoordinate, float phase, float amplitude)" "{" "vec2 yc = texture(texID, coordinate).rg / vec2(255.0);" - "float phaseOffset = 6.283185308 * float(yc.y);" + "float phaseOffset = 6.283185308 * 2.0 * yc.y;" "float chroma = cos(phase + phaseOffset);" - "return mix(yc.x, chroma, amplitude);" + "return mix(yc.x, step(yc.y, 0.75) * chroma, amplitude);" "}"); // default to NTSC @@ -91,7 +91,7 @@ template class MOS6560 { 6, 7, 5, 13, 2, 10, 0, 8, }; const uint8_t ntsc_chrominances[16] = { - 15, 15, 2, 10, 4, 12, 6, 14, + 255, 255, 2, 10, 4, 12, 6, 14, 0, 8, 2, 10, 4, 12, 6, 14, }; const uint8_t *chrominances; @@ -118,7 +118,7 @@ template class MOS6560 { } crt_->set_new_display_type((unsigned int)(timing_.cycles_per_line*4), display_type); - crt_->set_visible_area(Outputs::CRT::Rect(0.05f, 0.05f, 0.9f, 0.9f)); +// crt_->set_visible_area(Outputs::CRT::Rect(0.05f, 0.05f, 0.9f, 0.9f)); // switch(output_mode) { // case OutputMode::PAL: From b0142cf0507737d1563a3243261a465723073ca1 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 13 May 2017 14:29:36 -0400 Subject: [PATCH 4/7] Made an updated stab at NTSC colours. --- Components/6560/6560.hpp | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/Components/6560/6560.hpp b/Components/6560/6560.hpp index fccf4e053..575d78a15 100644 --- a/Components/6560/6560.hpp +++ b/Components/6560/6560.hpp @@ -57,7 +57,7 @@ template class MOS6560 { "float phaseOffset = 6.283185308 * 2.0 * yc.y;" "float chroma = cos(phase + phaseOffset);" - "return mix(yc.x, step(yc.y, 0.75) * chroma, amplitude);" + "return mix(yc.x, step(yc.y, 0.75) * 0.5 * chroma, amplitude);" "}"); // default to NTSC @@ -80,19 +80,25 @@ template class MOS6560 { */ void set_output_mode(OutputMode output_mode) { output_mode_ = output_mode; + + // Lumunances are encoded trivially: on a 0–255 scale. const uint8_t luminances[16] = { 0, 255, 91, 190, 134, 176, 84, 224, 140, 212, 200, 213, 205, 200, 163, 221 }; + + // Chrominances are encoded such that 0–128 is a complete revolution of phase; + // anything above 191 disables the colour subcarrier. Phase is relative to the + // colour burst, so 0 is green. const uint8_t pal_chrominances[16] = { 15, 15, 5, 13, 2, 10, 0, 8, 6, 7, 5, 13, 2, 10, 0, 8, }; const uint8_t ntsc_chrominances[16] = { - 255, 255, 2, 10, 4, 12, 6, 14, - 0, 8, 2, 10, 4, 12, 6, 14, + 255, 255, 40, 104, 64, 120, 80, 16, + 32, 32, 40, 104, 64, 120, 80, 16, }; const uint8_t *chrominances; Outputs::CRT::DisplayType display_type; @@ -132,7 +138,7 @@ template class MOS6560 { for(int c = 0; c < 16; c++) { uint8_t *colour = (uint8_t *)&colours_[c]; colour[0] = luminances[c]; - colour[1] = chrominances[c] * 15; + colour[1] = chrominances[c]; } } @@ -297,6 +303,15 @@ template class MOS6560 { pixel_pointer[6] = pixel_pointer[7] = colours[(character_value_ >> 0)&3]; } + +// pixel_pointer[0] = +// pixel_pointer[1] = +// pixel_pointer[2] = +// pixel_pointer[3] = +// pixel_pointer[4] = +// pixel_pointer[5] = +// pixel_pointer[6] = +// pixel_pointer[7] = colours_[8]; pixel_pointer += 8; } } else { From 44ce7fa54ceba42387916538d1d7ecef23d522be Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 13 May 2017 21:50:09 -0400 Subject: [PATCH 5/7] Corrected luminances across the board, and PAL colours. --- Components/6560/6560.hpp | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/Components/6560/6560.hpp b/Components/6560/6560.hpp index 575d78a15..ec1ba9631 100644 --- a/Components/6560/6560.hpp +++ b/Components/6560/6560.hpp @@ -83,22 +83,26 @@ template class MOS6560 { // Lumunances are encoded trivially: on a 0–255 scale. const uint8_t luminances[16] = { - 0, 255, 91, 190, - 134, 176, 84, 224, - 140, 212, 200, 213, - 205, 200, 163, 221 + 0, 255, 109, 189, + 199, 144, 159, 161, + 126, 227, 227, 207, + 235, 173, 188, 196 }; // Chrominances are encoded such that 0–128 is a complete revolution of phase; // anything above 191 disables the colour subcarrier. Phase is relative to the // colour burst, so 0 is green. const uint8_t pal_chrominances[16] = { - 15, 15, 5, 13, 2, 10, 0, 8, - 6, 7, 5, 13, 2, 10, 0, 8, + 255, 255, 40, 112, + 8, 88, 0, 56, + 40, 48, 40, 112, + 8, 88, 0, 56, }; const uint8_t ntsc_chrominances[16] = { - 255, 255, 40, 104, 64, 120, 80, 16, - 32, 32, 40, 104, 64, 120, 80, 16, + 255, 255, 40, 104, + 64, 120, 80, 16, + 32, 32, 40, 104, + 64, 120, 80, 16, }; const uint8_t *chrominances; Outputs::CRT::DisplayType display_type; @@ -124,7 +128,7 @@ template class MOS6560 { } crt_->set_new_display_type((unsigned int)(timing_.cycles_per_line*4), display_type); -// crt_->set_visible_area(Outputs::CRT::Rect(0.05f, 0.05f, 0.9f, 0.9f)); + crt_->set_visible_area(Outputs::CRT::Rect(0.05f, 0.05f, 0.9f, 0.9f)); // switch(output_mode) { // case OutputMode::PAL: @@ -304,14 +308,6 @@ template class MOS6560 { pixel_pointer[7] = colours[(character_value_ >> 0)&3]; } -// pixel_pointer[0] = -// pixel_pointer[1] = -// pixel_pointer[2] = -// pixel_pointer[3] = -// pixel_pointer[4] = -// pixel_pointer[5] = -// pixel_pointer[6] = -// pixel_pointer[7] = colours_[8]; pixel_pointer += 8; } } else { From c2b5a9bb1f3448522f032a2d8b8d789a833385bd Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 13 May 2017 21:50:48 -0400 Subject: [PATCH 6/7] Minor fix: given that phase is now a function of position, stop nudging position. --- Outputs/CRT/Internals/Shaders/IntermediateShader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp b/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp index 9c81a3421..670effaeb 100644 --- a/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp +++ b/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp @@ -99,7 +99,7 @@ std::unique_ptr IntermediateShader::make_shader(const std::s "phaseAndAmplitudeVarying.y = 0.33;" // TODO: reinstate connection with (phaseTimeAndAmplitude.y/256.0) // determine output position by scaling the output position according to the texture size - "vec2 eyePosition = 2.0*(extendedOutputPosition / outputTextureSize) - vec2(1.0) + vec2(1.0)/outputTextureSize;" + "vec2 eyePosition = 2.0*(extendedOutputPosition / outputTextureSize) - vec2(1.0);" "gl_Position = vec4(eyePosition, 0.0, 1.0);" "}", sampler_type, input_variable); From e270b726b30a790d14f98c261de1c9e2eaa380e5 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 13 May 2017 22:01:02 -0400 Subject: [PATCH 7/7] Tweaked blue, increased saturation. --- Components/6560/6560.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Components/6560/6560.hpp b/Components/6560/6560.hpp index ec1ba9631..0067dec43 100644 --- a/Components/6560/6560.hpp +++ b/Components/6560/6560.hpp @@ -57,7 +57,7 @@ template class MOS6560 { "float phaseOffset = 6.283185308 * 2.0 * yc.y;" "float chroma = cos(phase + phaseOffset);" - "return mix(yc.x, step(yc.y, 0.75) * 0.5 * chroma, amplitude);" + "return mix(yc.x, step(yc.y, 0.75) * chroma, amplitude);" "}"); // default to NTSC @@ -94,9 +94,9 @@ template class MOS6560 { // colour burst, so 0 is green. const uint8_t pal_chrominances[16] = { 255, 255, 40, 112, - 8, 88, 0, 56, + 8, 88, 120, 56, 40, 48, 40, 112, - 8, 88, 0, 56, + 8, 88, 120, 56, }; const uint8_t ntsc_chrominances[16] = { 255, 255, 40, 104,