From 8232ed765e468da77c0c9c18035b344d24ab546e Mon Sep 17 00:00:00 2001
From: Thomas Harte <thomas.harte@gmail.com>
Date: Wed, 20 Apr 2016 20:44:25 -0400
Subject: [PATCH] Eliminated use of zero-alpha runs to clear new lines in the
 intermediate buffer in favour of a scissored glClear. It's just an easier way
 to scale the current approach to three intermediate buffers.

---
 Outputs/CRT/CRT.cpp                 | 10 -----
 Outputs/CRT/Internals/CRTOpenGL.cpp | 61 +++++++++++++++++++++++++----
 Outputs/CRT/Internals/CRTOpenGL.hpp |  6 +--
 3 files changed, 56 insertions(+), 21 deletions(-)

diff --git a/Outputs/CRT/CRT.cpp b/Outputs/CRT/CRT.cpp
index 50ef7a3a1..91567e77c 100644
--- a/Outputs/CRT/CRT.cpp
+++ b/Outputs/CRT/CRT.cpp
@@ -106,7 +106,6 @@ Flywheel::SyncEvent CRT::get_next_horizontal_sync_event(bool hsync_is_requested,
 #define source_output_position_y(v)	(*(uint16_t *)&next_run[SourceVertexSize*v + SourceVertexOffsetOfOutputPosition + 2])
 #define source_phase(v)				next_run[SourceVertexSize*v + SourceVertexOffsetOfPhaseAmplitudeAndAlpha + 0]
 #define source_amplitude(v)			next_run[SourceVertexSize*v + SourceVertexOffsetOfPhaseAmplitudeAndAlpha + 1]
-#define source_alpha(v)				next_run[SourceVertexSize*v + SourceVertexOffsetOfPhaseAmplitudeAndAlpha + 2]
 #define source_phase_time(v)		(*(uint16_t *)&next_run[SourceVertexSize*v + SourceVertexOffsetOfPhaseTime])
 
 void CRT::advance_cycles(unsigned int number_of_cycles, unsigned int source_divider, bool hsync_requested, bool vsync_requested, const bool vsync_charging, const Scan::Type type, uint16_t tex_x, uint16_t tex_y)
@@ -165,7 +164,6 @@ void CRT::advance_cycles(unsigned int number_of_cycles, unsigned int source_divi
 				source_phase(0) = source_phase(1) = _colour_burst_phase;
 				source_amplitude(0) = source_amplitude(1) = _colour_burst_amplitude;
 				source_phase_time(0) = source_phase_time(1) = _colour_burst_time;
-				source_alpha(0) = source_alpha(1) = 255;
 			}
 		}
 
@@ -244,14 +242,6 @@ void CRT::advance_cycles(unsigned int number_of_cycles, unsigned int source_divi
 			if(next_run_length == time_until_horizontal_sync_event && next_horizontal_sync_event == Flywheel::SyncEvent::StartRetrace)
 			{
 				_openGL_output_builder->increment_composite_output_y();
-
-				// store a run to clear the new line
-				next_run = _openGL_output_builder->get_next_source_run();
-				source_output_position_x(0) = 0;
-				source_output_position_x(1) = IntermediateBufferWidth;
-				source_output_position_y(0) = source_output_position_y(1) = _openGL_output_builder->get_composite_output_y();
-				source_alpha(0) = source_alpha(1) = 0;
-				_openGL_output_builder->complete_source_run();
 			}
 		}
 
diff --git a/Outputs/CRT/Internals/CRTOpenGL.cpp b/Outputs/CRT/Internals/CRTOpenGL.cpp
index f887a0456..a9ea0d8b0 100644
--- a/Outputs/CRT/Internals/CRTOpenGL.cpp
+++ b/Outputs/CRT/Internals/CRTOpenGL.cpp
@@ -206,12 +206,59 @@ void OpenGLOutputBuilder::draw_frame(unsigned int output_width, unsigned int out
 		// decide how much to draw
 		if(_drawn_source_buffer_data_pointer != _source_buffer_data_pointer)
 		{
+			// determine how many lines are newly reclaimed; they'll need to be cleared
+			uint16_t clearing_zones[4];
+			int number_of_clearing_zones = 0;
+
+			if(_composite_src_output_y != _cleared_composite_output_y)
+			{
+				uint16_t lines_to_clear = _composite_src_output_y - _cleared_composite_output_y;
+				if(lines_to_clear > IntermediateBufferHeight)
+				{
+					number_of_clearing_zones = 1;
+					clearing_zones[0] = 0;
+					clearing_zones[1] = IntermediateBufferHeight;
+				}
+				else
+				{
+					clearing_zones[0] = (_cleared_composite_output_y+1)%IntermediateBufferHeight;
+					if(clearing_zones[0]+lines_to_clear < IntermediateBufferHeight)
+					{
+						clearing_zones[1] = lines_to_clear;
+						number_of_clearing_zones = 1;
+					}
+					else
+					{
+						clearing_zones[1] = IntermediateBufferHeight - clearing_zones[0];
+						clearing_zones[2] = 0;
+						clearing_zones[3] = lines_to_clear - clearing_zones[1];
+						number_of_clearing_zones = 2;
+					}
+				}
+
+				_composite_src_output_y %= IntermediateBufferHeight;
+				_cleared_composite_output_y = _composite_src_output_y;
+			}
+
+			// all drawing will be from the source vertex array and without blending
+			glBindVertexArray(source_vertex_array);
+			glDisable(GL_BLEND);
+
+			// switch to the initial texture
+			compositeTexture->bind_framebuffer();
 			composite_input_shader_program->bind();
 
-			compositeTexture->bind_framebuffer();
-			glBindVertexArray(source_vertex_array);
-
-			glDisable(GL_BLEND);
+			// clear as desired
+			if(number_of_clearing_zones)
+			{
+				glEnable(GL_SCISSOR_TEST);
+				for(int c = 0; c < number_of_clearing_zones; c++)
+				{
+					glScissor(0, clearing_zones[c*2], IntermediateBufferWidth, clearing_zones[c*2 + 1]);
+					glClear(GL_COLOR_BUFFER_BIT);
+				}
+				glDisable(GL_SCISSOR_TEST);
+			}
 
 			size_t new_data_size = _source_buffer_data_pointer - _drawn_source_buffer_data_pointer;
 			size_t new_data_start = _drawn_source_buffer_data_pointer;
@@ -231,6 +278,7 @@ void OpenGLOutputBuilder::draw_frame(unsigned int output_width, unsigned int out
 				glDrawArrays(GL_LINES, 0, (GLsizei)((new_data_size - first_data_length) / SourceVertexSize));
 			}
 
+			// switch back to screen output
 			glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebuffer);
 			glViewport(0, 0, (GLsizei)output_width, (GLsizei)output_height);
 		}
@@ -358,7 +406,6 @@ char *OpenGLOutputBuilder::get_input_vertex_shader()
 		"out vec2 inputPositionVarying;"
 		"out vec2 iInputPositionVarying;"
 		"out float phaseVarying;"
-		"out float alphaVarying;"
 
 		"void main(void)"
 		"{"
@@ -367,7 +414,6 @@ char *OpenGLOutputBuilder::get_input_vertex_shader()
 			"inputPositionVarying = (inputPosition + vec2(0.0, 0.5)) / vec2(textureSize);"
 
 			"phaseVarying = (phaseCyclesPerTick * phaseTime + phaseAmplitudeAndAlpha.x) * 2.0 * 3.141592654;"
-			"alphaVarying = phaseAmplitudeAndAlpha.z;"
 
 			"vec2 eyePosition = 2.0*(outputPosition / outputTextureSize) - vec2(1.0) + vec2(0.5)/textureSize;"
 			"gl_Position = vec4(eyePosition, 0.0, 1.0);"
@@ -390,7 +436,6 @@ char *OpenGLOutputBuilder::get_input_fragment_shader()
 		"in vec2 inputPositionVarying;"
 		"in vec2 iInputPositionVarying;"
 		"in float phaseVarying;"
-		"in float alphaVarying;"
 
 		"out vec4 fragColour;"
 
@@ -400,7 +445,7 @@ char *OpenGLOutputBuilder::get_input_fragment_shader()
 
 		"void main(void)"
 		"{"
-			"fragColour = vec4(rgb_sample(texID, inputPositionVarying, iInputPositionVarying) * alphaVarying, 1.0);" // composite
+			"fragColour = vec4(rgb_sample(texID, inputPositionVarying, iInputPositionVarying), 1.0);"
 		"}"
 	, composite_shader);
 	return result;
diff --git a/Outputs/CRT/Internals/CRTOpenGL.hpp b/Outputs/CRT/Internals/CRTOpenGL.hpp
index 26307df82..6da878397 100644
--- a/Outputs/CRT/Internals/CRTOpenGL.hpp
+++ b/Outputs/CRT/Internals/CRTOpenGL.hpp
@@ -60,7 +60,7 @@ class OpenGLOutputBuilder {
 		std::shared_ptr<std::mutex> _output_mutex;
 
 		// transient buffers indicating composite data not yet decoded
-		uint16_t _composite_src_output_y;
+		uint16_t _composite_src_output_y, _cleared_composite_output_y;
 
 		char *get_output_vertex_shader(const char *header);
 		char *get_rgb_output_vertex_shader();
@@ -150,12 +150,12 @@ class OpenGLOutputBuilder {
 
 		inline uint16_t get_composite_output_y()
 		{
-			return _composite_src_output_y;
+			return _composite_src_output_y % IntermediateBufferHeight;
 		}
 
 		inline void increment_composite_output_y()
 		{
-			_composite_src_output_y = (_composite_src_output_y + 1) % IntermediateBufferHeight;
+			_composite_src_output_y++;
 		}
 
 		inline void increment_field()