From f2b8b26bc46f431b81c852de95fdae7821eb5a84 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 3 Jan 2017 21:16:38 -0500 Subject: [PATCH 01/26] Started throwing some comments into my shaders. --- Outputs/CRT/Internals/Shaders/IntermediateShader.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp b/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp index b3ad6f5a8..efabbf7d5 100644 --- a/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp +++ b/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp @@ -53,19 +53,28 @@ std::unique_ptr IntermediateShader::make_shader(const char * "void main(void)" "{" + // odd vertices are on the left, even on the right "float extent = float(gl_VertexID & 1);" + // inputPosition.x is either inputStart.x or ends.x, depending on whether it is on the left or the right; + // outputPosition.x is either outputStart.x or ends.y; + // .ys are inputStart.y and outputStart.y respectively "vec2 inputPosition = vec2(mix(inputStart.x, ends.x, extent), inputStart.y);" "vec2 outputPosition = vec2(mix(outputStart.x, ends.y, extent), outputStart.y);" + + // extension is the amount to extend both the input and output by to add a full colour cycle at each end "vec2 extensionVector = vec2(extension, 0.0) * 2.0 * (extent - 0.5);" + // extended[Input/Output]Position are [input/output]Position with the necessary applied extension "vec2 extendedInputPosition = %s + extensionVector;" "vec2 extendedOutputPosition = outputPosition + extensionVector;" + // keep iInputPositionVarying in whole source pixels, scale mappedInputPosition to the ordinary normalised range "vec2 textureSize = vec2(textureSize(texID, 0));" "iInputPositionVarying = extendedInputPosition;" "vec2 mappedInputPosition = (extendedInputPosition + vec2(0.0, 0.5)) / textureSize;" + // setup input positions spaced as per the supplied offsets; these are for filtering where required "inputPositionsVarying[0] = mappedInputPosition - (vec2(offsets[0], 0.0) / textureSize);" "inputPositionsVarying[1] = mappedInputPosition - (vec2(offsets[1], 0.0) / textureSize);" "inputPositionsVarying[2] = mappedInputPosition - (vec2(offsets[2], 0.0) / textureSize);" @@ -79,9 +88,12 @@ std::unique_ptr IntermediateShader::make_shader(const char * "inputPositionsVarying[10] = mappedInputPosition + (vec2(offsets[0], 0.0) / textureSize);" "delayLinePositionVarying = mappedInputPosition - vec2(0.0, 1.0);" + // setup phaseAndAmplitudeVarying.x as colour burst subcarrier phase, in radians; + // setup phaseAndAmplitudeVarying.x as colour burst amplitude "phaseAndAmplitudeVarying.x = (phaseCyclesPerTick * (extendedOutputPosition.x - phaseTimeAndAmplitude.y) + (phaseTimeAndAmplitude.x / 256.0)) * 2.0 * 3.141592654;" "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;" "gl_Position = vec4(eyePosition, 0.0, 1.0);" "}", sampler_type, input_variable); From 7d60df9075cdc9883034a7b936ff0e8525ec0c9b Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 3 Jan 2017 22:16:52 -0500 Subject: [PATCH 02/26] Added the option for both intermediate and output shaders to use only a portion of the input/output texture; made an attempt to pick an appropriate proportion in order to align signal sampling with the colour subcarrier. --- Outputs/CRT/Internals/CRTOpenGL.cpp | 41 ++++++++++++++++--- .../Internals/Shaders/IntermediateShader.cpp | 10 ++++- .../Internals/Shaders/IntermediateShader.hpp | 6 +++ .../CRT/Internals/Shaders/OutputShader.cpp | 8 +++- .../CRT/Internals/Shaders/OutputShader.hpp | 6 +++ Outputs/CRT/Internals/Shaders/Shader.cpp | 3 +- 6 files changed, 64 insertions(+), 10 deletions(-) diff --git a/Outputs/CRT/Internals/CRTOpenGL.cpp b/Outputs/CRT/Internals/CRTOpenGL.cpp index 6296b3e61..6ad598b9f 100644 --- a/Outputs/CRT/Internals/CRTOpenGL.cpp +++ b/Outputs/CRT/Internals/CRTOpenGL.cpp @@ -381,11 +381,40 @@ void OpenGLOutputBuilder::set_timing_uniforms() extends = true; } - if(output_shader_program_) output_shader_program_->set_timing(height_of_display_, cycles_per_line_, horizontal_scan_period_, vertical_scan_period_, vertical_period_divider_); - float colour_subcarrier_frequency = (float)colour_cycle_numerator_ / (float)colour_cycle_denominator_; - if(composite_separation_filter_program_) composite_separation_filter_program_->set_separation_frequency(cycles_per_line_, colour_subcarrier_frequency); - if(composite_y_filter_shader_program_) composite_y_filter_shader_program_->set_filter_coefficients(cycles_per_line_, colour_subcarrier_frequency * 0.25f); - if(composite_chrominance_filter_shader_program_) composite_chrominance_filter_shader_program_->set_filter_coefficients(cycles_per_line_, colour_subcarrier_frequency * 0.5f); - if(rgb_filter_shader_program_) rgb_filter_shader_program_->set_filter_coefficients(cycles_per_line_, (float)input_frequency_ * 0.5f); + float output_width = ((float)colour_cycle_numerator_ * 4.0f) / (float)(colour_cycle_denominator_ * IntermediateBufferWidth); + + if(composite_separation_filter_program_) + { + composite_separation_filter_program_->set_width_scalers(output_width, output_width); + composite_separation_filter_program_->set_separation_frequency(cycles_per_line_, colour_subcarrier_frequency); + } + if(composite_y_filter_shader_program_) + { + composite_y_filter_shader_program_->set_width_scalers(output_width, output_width); + composite_y_filter_shader_program_->set_filter_coefficients(cycles_per_line_, colour_subcarrier_frequency * 0.25f); + } + if(composite_chrominance_filter_shader_program_) + { + composite_chrominance_filter_shader_program_->set_width_scalers(output_width, output_width); + composite_chrominance_filter_shader_program_->set_filter_coefficients(cycles_per_line_, colour_subcarrier_frequency * 0.5f); + } + if(rgb_filter_shader_program_) + { + rgb_filter_shader_program_->set_width_scalers(output_width, output_width); + rgb_filter_shader_program_->set_filter_coefficients(cycles_per_line_, (float)input_frequency_ * 0.5f); + } + if(output_shader_program_) + { + output_shader_program_->set_input_width_scaler(output_width); + output_shader_program_->set_timing(height_of_display_, cycles_per_line_, horizontal_scan_period_, vertical_scan_period_, vertical_period_divider_); + } + if(composite_input_shader_program_) + { + composite_input_shader_program_->set_width_scalers(1.0f, output_width); + } + if(rgb_input_shader_program_) + { + rgb_input_shader_program_->set_width_scalers(1.0f, output_width); + } } diff --git a/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp b/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp index efabbf7d5..abc21433a 100644 --- a/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp +++ b/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp @@ -45,6 +45,7 @@ std::unique_ptr IntermediateShader::make_shader(const char * "uniform float extension;" "uniform %s texID;" "uniform float offsets[5];" + "uniform vec2 widthScalers;" "out vec2 phaseAndAmplitudeVarying;" "out vec2 inputPositionsVarying[11];" @@ -59,8 +60,8 @@ std::unique_ptr IntermediateShader::make_shader(const char * // inputPosition.x is either inputStart.x or ends.x, depending on whether it is on the left or the right; // outputPosition.x is either outputStart.x or ends.y; // .ys are inputStart.y and outputStart.y respectively - "vec2 inputPosition = vec2(mix(inputStart.x, ends.x, extent), inputStart.y);" - "vec2 outputPosition = vec2(mix(outputStart.x, ends.y, extent), outputStart.y);" + "vec2 inputPosition = vec2(mix(inputStart.x, ends.x, extent)*widthScalers[0], inputStart.y);" + "vec2 outputPosition = vec2(mix(outputStart.x, ends.y, extent)*widthScalers[1], outputStart.y);" // extension is the amount to extend both the input and output by to add a full colour cycle at each end "vec2 extensionVector = vec2(extension, 0.0) * 2.0 * (extent - 0.5);" @@ -477,3 +478,8 @@ void IntermediateShader::set_colour_conversion_matrices(float *fromRGB, float *t set_uniform_matrix("lumaChromaToRGB", 3, false, toRGB); set_uniform_matrix("rgbToLumaChroma", 3, false, fromRGB); } + +void IntermediateShader::set_width_scalers(float input_scaler, float output_scaler) +{ + set_uniform("widthScalers", input_scaler, output_scaler); +} diff --git a/Outputs/CRT/Internals/Shaders/IntermediateShader.hpp b/Outputs/CRT/Internals/Shaders/IntermediateShader.hpp index a419da8be..63402fb88 100644 --- a/Outputs/CRT/Internals/Shaders/IntermediateShader.hpp +++ b/Outputs/CRT/Internals/Shaders/IntermediateShader.hpp @@ -88,6 +88,12 @@ public: */ void set_colour_conversion_matrices(float *fromRGB, float *toRGB); + /*! + Sets the proportions of the input and output areas that should be considered the whole width — 1.0 means use all available + space, 0.5 means use half, etc. + */ + void set_width_scalers(float input_scaler, float output_scaler); + private: static std::unique_ptr make_shader(const char *fragment_shader, bool use_usampler, bool input_is_inputPosition); }; diff --git a/Outputs/CRT/Internals/Shaders/OutputShader.cpp b/Outputs/CRT/Internals/Shaders/OutputShader.cpp index e139c954d..86f0f928c 100644 --- a/Outputs/CRT/Internals/Shaders/OutputShader.cpp +++ b/Outputs/CRT/Internals/Shaders/OutputShader.cpp @@ -38,6 +38,7 @@ std::unique_ptr OutputShader::make_shader(const char *fragment_met "uniform vec2 positionConversion;" "uniform vec2 scanNormal;" "uniform %s texID;" + "uniform float inputScaler;" "out float lateralVarying;" "out vec2 srcCoordinatesVarying;" @@ -54,7 +55,7 @@ std::unique_ptr OutputShader::make_shader(const char *fragment_met "vec2 vSrcCoordinates = vec2(x, vertical.y);" "ivec2 textureSize = textureSize(texID, 0);" "iSrcCoordinatesVarying = vSrcCoordinates;" - "srcCoordinatesVarying = vec2(vSrcCoordinates.x / textureSize.x, (vSrcCoordinates.y + 0.5) / textureSize.y);" + "srcCoordinatesVarying = vec2(inputScaler * vSrcCoordinates.x / textureSize.x, (vSrcCoordinates.y + 0.5) / textureSize.y);" "vec2 vPosition = vec2(x, vertical.x);" "vec2 floatingPosition = (vPosition / positionConversion) + lateral * scanNormal;" @@ -117,3 +118,8 @@ void OutputShader::set_timing(unsigned int height_of_display, unsigned int cycle set_uniform("scanNormal", scan_normal[0], scan_normal[1]); set_uniform("positionConversion", (GLfloat)horizontal_scan_period, (GLfloat)vertical_scan_period / (GLfloat)vertical_period_divider); } + +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 9b4b7db39..44f4ec041 100644 --- a/Outputs/CRT/Internals/Shaders/OutputShader.hpp +++ b/Outputs/CRT/Internals/Shaders/OutputShader.hpp @@ -58,6 +58,12 @@ public: to occur upon the next `bind`. */ void set_timing(unsigned int height_of_display, unsigned int cycles_per_line, unsigned int horizontal_scan_period, unsigned int vertical_scan_period, unsigned int vertical_period_divider); + + /*! + 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. + */ + void set_input_width_scaler(float input_scaler); }; } diff --git a/Outputs/CRT/Internals/Shaders/Shader.cpp b/Outputs/CRT/Internals/Shaders/Shader.cpp index df96c14ab..15b8bb43c 100644 --- a/Outputs/CRT/Internals/Shaders/Shader.cpp +++ b/Outputs/CRT/Internals/Shaders/Shader.cpp @@ -156,7 +156,8 @@ void Shader::set_uniform(const std::string &name, GLint value1, GLint value2) void Shader::set_uniform(const std::string &name, GLfloat value1, GLfloat value2) { enqueue_function([name, value1, value2, this] { - glUniform2f(location(), value1, value2); + GLint location = location(); + glUniform2f(location, value1, value2); }); } From a83612094585cc6b588e1bd014266b3daf9c15a9 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 3 Jan 2017 22:32:07 -0500 Subject: [PATCH 03/26] =?UTF-8?q?Restored=20proper=20colour=20separation,?= =?UTF-8?q?=20but=20somewhere=20a=20massive=20hit=20in=20horizontal=20reso?= =?UTF-8?q?lution=20is=20happening=20=E2=80=94=20much=20greater=20than=20o?= =?UTF-8?q?ne=20would=20expect=20from=20the=20sample=20size=20picked.=20So?= =?UTF-8?q?=20investigation=20to=20come.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Outputs/CRT/Internals/CRTConstants.hpp | 2 +- Outputs/CRT/Internals/CRTOpenGL.cpp | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Outputs/CRT/Internals/CRTConstants.hpp b/Outputs/CRT/Internals/CRTConstants.hpp index b7fefe8b9..54f14edbe 100644 --- a/Outputs/CRT/Internals/CRTConstants.hpp +++ b/Outputs/CRT/Internals/CRTConstants.hpp @@ -36,7 +36,7 @@ const GLsizei InputBufferBuilderWidth = 2048; const GLsizei InputBufferBuilderHeight = 512; // This is the size of the intermediate buffers used during composite to RGB conversion -const GLsizei IntermediateBufferWidth = 4096; +const GLsizei IntermediateBufferWidth = 2048; const GLsizei IntermediateBufferHeight = 512; // Some internal buffer sizes diff --git a/Outputs/CRT/Internals/CRTOpenGL.cpp b/Outputs/CRT/Internals/CRTOpenGL.cpp index 6ad598b9f..01535b2d3 100644 --- a/Outputs/CRT/Internals/CRTOpenGL.cpp +++ b/Outputs/CRT/Internals/CRTOpenGL.cpp @@ -383,26 +383,27 @@ void OpenGLOutputBuilder::set_timing_uniforms() float colour_subcarrier_frequency = (float)colour_cycle_numerator_ / (float)colour_cycle_denominator_; float output_width = ((float)colour_cycle_numerator_ * 4.0f) / (float)(colour_cycle_denominator_ * IntermediateBufferWidth); + float sample_cycles_per_line = cycles_per_line_ / output_width; if(composite_separation_filter_program_) { composite_separation_filter_program_->set_width_scalers(output_width, output_width); - composite_separation_filter_program_->set_separation_frequency(cycles_per_line_, colour_subcarrier_frequency); + composite_separation_filter_program_->set_separation_frequency(sample_cycles_per_line, colour_subcarrier_frequency); } if(composite_y_filter_shader_program_) { composite_y_filter_shader_program_->set_width_scalers(output_width, output_width); - composite_y_filter_shader_program_->set_filter_coefficients(cycles_per_line_, colour_subcarrier_frequency * 0.25f); + composite_y_filter_shader_program_->set_filter_coefficients(sample_cycles_per_line, colour_subcarrier_frequency * 0.25f); } if(composite_chrominance_filter_shader_program_) { composite_chrominance_filter_shader_program_->set_width_scalers(output_width, output_width); - composite_chrominance_filter_shader_program_->set_filter_coefficients(cycles_per_line_, colour_subcarrier_frequency * 0.5f); + composite_chrominance_filter_shader_program_->set_filter_coefficients(sample_cycles_per_line, colour_subcarrier_frequency * 0.5f); } if(rgb_filter_shader_program_) { rgb_filter_shader_program_->set_width_scalers(output_width, output_width); - rgb_filter_shader_program_->set_filter_coefficients(cycles_per_line_, (float)input_frequency_ * 0.5f); + rgb_filter_shader_program_->set_filter_coefficients(sample_cycles_per_line, (float)input_frequency_ * 0.5f); } if(output_shader_program_) { From aa7774a9a614119da947f2280caa208878380963 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 3 Jan 2017 22:41:34 -0500 Subject: [PATCH 04/26] Experimental: up the chroma accuracy, just let the luma go straight through. Subject to figuring out how I'm still losing so much precision. --- Outputs/CRT/Internals/CRTOpenGL.cpp | 2 +- .../Internals/Shaders/IntermediateShader.cpp | 55 ++++++++++--------- 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/Outputs/CRT/Internals/CRTOpenGL.cpp b/Outputs/CRT/Internals/CRTOpenGL.cpp index 01535b2d3..dd903b468 100644 --- a/Outputs/CRT/Internals/CRTOpenGL.cpp +++ b/Outputs/CRT/Internals/CRTOpenGL.cpp @@ -398,7 +398,7 @@ void OpenGLOutputBuilder::set_timing_uniforms() if(composite_chrominance_filter_shader_program_) { composite_chrominance_filter_shader_program_->set_width_scalers(output_width, output_width); - composite_chrominance_filter_shader_program_->set_filter_coefficients(sample_cycles_per_line, colour_subcarrier_frequency * 0.5f); + composite_chrominance_filter_shader_program_->set_filter_coefficients(sample_cycles_per_line, colour_subcarrier_frequency); } if(rgb_filter_shader_program_) { diff --git a/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp b/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp index abc21433a..0c7086881 100644 --- a/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp +++ b/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp @@ -302,34 +302,35 @@ std::unique_ptr IntermediateShader::make_luma_filter_shader( "void main(void)" "{" - "vec3 samples[] = vec3[](" - "texture(texID, inputPositionsVarying[0]).rgb," - "texture(texID, inputPositionsVarying[1]).rgb," - "texture(texID, inputPositionsVarying[2]).rgb," - "texture(texID, inputPositionsVarying[3]).rgb," - "texture(texID, inputPositionsVarying[4]).rgb," - "texture(texID, inputPositionsVarying[5]).rgb," - "texture(texID, inputPositionsVarying[6]).rgb," - "texture(texID, inputPositionsVarying[7]).rgb," - "texture(texID, inputPositionsVarying[8]).rgb," - "texture(texID, inputPositionsVarying[9]).rgb," - "texture(texID, inputPositionsVarying[10]).rgb" - ");" +// "vec3 samples[] = vec3[](" +// "texture(texID, inputPositionsVarying[0]).rgb," +// "texture(texID, inputPositionsVarying[1]).rgb," +// "texture(texID, inputPositionsVarying[2]).rgb," +// "texture(texID, inputPositionsVarying[3]).rgb," +// "texture(texID, inputPositionsVarying[4]).rgb," +// "texture(texID, inputPositionsVarying[5]).rgb," +// "texture(texID, inputPositionsVarying[6]).rgb," +// "texture(texID, inputPositionsVarying[7]).rgb," +// "texture(texID, inputPositionsVarying[8]).rgb," +// "texture(texID, inputPositionsVarying[9]).rgb," +// "texture(texID, inputPositionsVarying[10]).rgb" +// ");" +// +// "vec4 luminance[] = vec4[](" +// "vec4(samples[0].r, samples[1].r, samples[2].r, samples[3].r)," +// "vec4(samples[4].r, samples[5].r, samples[6].r, samples[7].r)," +// "vec4(samples[8].r, samples[9].r, samples[10].r, 0.0)" +// ");" - "vec4 luminance[] = vec4[](" - "vec4(samples[0].r, samples[1].r, samples[2].r, samples[3].r)," - "vec4(samples[4].r, samples[5].r, samples[6].r, samples[7].r)," - "vec4(samples[8].r, samples[9].r, samples[10].r, 0.0)" - ");" - - "fragColour = vec3(" - "dot(vec3(" - "dot(luminance[0], weights[0])," - "dot(luminance[1], weights[1])," - "dot(luminance[2], weights[2])" - "), vec3(1.0))," - "samples[5].gb" - ");" +// "fragColour = vec3(" +// "dot(vec3(" +// "dot(luminance[0], weights[0])," +// "dot(luminance[1], weights[1])," +// "dot(luminance[2], weights[2])" +// "), vec3(1.0))," +// "samples[5].gb" +// ");" + "fragColour = texture(texID, inputPositionsVarying[5]).rgb;"//lumaChromaToRGB * lumaChromaColourInRange;" "}", false, false); } From c746a3711f9b84586b00e488969e6615b91803fe Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 4 Jan 2017 08:06:18 -0500 Subject: [PATCH 05/26] Temporarily disabled my attempt to be clever with bilinear filtering when applying a lowpass filter. Will need to investigate. --- Outputs/CRT/Internals/CRTOpenGL.cpp | 2 +- .../Internals/Shaders/IntermediateShader.cpp | 122 ++++++++++-------- Outputs/CRT/Internals/TextureTarget.cpp | 2 +- 3 files changed, 70 insertions(+), 56 deletions(-) diff --git a/Outputs/CRT/Internals/CRTOpenGL.cpp b/Outputs/CRT/Internals/CRTOpenGL.cpp index dd903b468..48bc65d6a 100644 --- a/Outputs/CRT/Internals/CRTOpenGL.cpp +++ b/Outputs/CRT/Internals/CRTOpenGL.cpp @@ -393,7 +393,7 @@ void OpenGLOutputBuilder::set_timing_uniforms() if(composite_y_filter_shader_program_) { composite_y_filter_shader_program_->set_width_scalers(output_width, output_width); - composite_y_filter_shader_program_->set_filter_coefficients(sample_cycles_per_line, colour_subcarrier_frequency * 0.25f); + composite_y_filter_shader_program_->set_filter_coefficients(sample_cycles_per_line, colour_subcarrier_frequency); } if(composite_chrominance_filter_shader_program_) { diff --git a/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp b/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp index 0c7086881..69eaa8f15 100644 --- a/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp +++ b/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp @@ -193,6 +193,7 @@ std::unique_ptr IntermediateShader::make_chroma_luma_separat "void main(void)" "{" + // grab 11 samples "vec4 samples[3] = vec4[](" "vec4(" "texture(texID, inputPositionsVarying[0]).r," @@ -214,6 +215,7 @@ std::unique_ptr IntermediateShader::make_chroma_luma_separat ")" ");" + // apply the low-pass filter to separate luma "float luminance = " "dot(vec3(" "dot(samples[0], weights[0])," @@ -221,9 +223,12 @@ std::unique_ptr IntermediateShader::make_chroma_luma_separat "dot(samples[2], weights[2])" "), vec3(1.0));" + // define chroma to be whatever was here, minus luma "float chrominance = 0.5 * (samples[1].y - luminance) / phaseAndAmplitudeVarying.y;" "luminance /= (1.0 - phaseAndAmplitudeVarying.y);" + // split choma colours here, as the most direct place, writing out + // RGB = (luma, chroma.x, chroma.y) "vec2 quadrature = vec2(cos(phaseAndAmplitudeVarying.x), -sin(phaseAndAmplitudeVarying.x));" "fragColour = vec3(luminance, vec2(0.5) + (chrominance * quadrature));" "}",false, false); @@ -302,35 +307,35 @@ std::unique_ptr IntermediateShader::make_luma_filter_shader( "void main(void)" "{" -// "vec3 samples[] = vec3[](" -// "texture(texID, inputPositionsVarying[0]).rgb," -// "texture(texID, inputPositionsVarying[1]).rgb," -// "texture(texID, inputPositionsVarying[2]).rgb," -// "texture(texID, inputPositionsVarying[3]).rgb," -// "texture(texID, inputPositionsVarying[4]).rgb," -// "texture(texID, inputPositionsVarying[5]).rgb," -// "texture(texID, inputPositionsVarying[6]).rgb," -// "texture(texID, inputPositionsVarying[7]).rgb," -// "texture(texID, inputPositionsVarying[8]).rgb," -// "texture(texID, inputPositionsVarying[9]).rgb," -// "texture(texID, inputPositionsVarying[10]).rgb" -// ");" -// -// "vec4 luminance[] = vec4[](" -// "vec4(samples[0].r, samples[1].r, samples[2].r, samples[3].r)," -// "vec4(samples[4].r, samples[5].r, samples[6].r, samples[7].r)," -// "vec4(samples[8].r, samples[9].r, samples[10].r, 0.0)" -// ");" + "vec3 samples[] = vec3[](" + "texture(texID, inputPositionsVarying[0]).rgb," + "texture(texID, inputPositionsVarying[1]).rgb," + "texture(texID, inputPositionsVarying[2]).rgb," + "texture(texID, inputPositionsVarying[3]).rgb," + "texture(texID, inputPositionsVarying[4]).rgb," + "texture(texID, inputPositionsVarying[5]).rgb," + "texture(texID, inputPositionsVarying[6]).rgb," + "texture(texID, inputPositionsVarying[7]).rgb," + "texture(texID, inputPositionsVarying[8]).rgb," + "texture(texID, inputPositionsVarying[9]).rgb," + "texture(texID, inputPositionsVarying[10]).rgb" + ");" -// "fragColour = vec3(" -// "dot(vec3(" -// "dot(luminance[0], weights[0])," -// "dot(luminance[1], weights[1])," -// "dot(luminance[2], weights[2])" -// "), vec3(1.0))," -// "samples[5].gb" -// ");" - "fragColour = texture(texID, inputPositionsVarying[5]).rgb;"//lumaChromaToRGB * lumaChromaColourInRange;" + "vec4 luminance[] = vec4[](" + "vec4(samples[0].r, samples[1].r, samples[2].r, samples[3].r)," + "vec4(samples[4].r, samples[5].r, samples[6].r, samples[7].r)," + "vec4(samples[8].r, samples[9].r, samples[10].r, 0.0)" + ");" + + "fragColour = vec3(" + "dot(vec3(" + "dot(luminance[0], weights[0])," + "dot(luminance[1], weights[1])," + "dot(luminance[2], weights[2])" + "), vec3(1.0))," + "samples[5].gb" + ");" +// "fragColour = texture(texID, inputPositionsVarying[5]).rgb;"//lumaChromaToRGB * lumaChromaColourInRange;" "}", false, false); } @@ -418,44 +423,53 @@ void IntermediateShader::set_filter_coefficients(float sampling_rate, float cuto // Perform a linear search for the highest number of taps we can use with 11 samples. GLfloat weights[12]; GLfloat offsets[5]; - unsigned int taps = 21; + unsigned int taps = 11; +// unsigned int taps = 21; while(1) { float coefficients[21]; SignalProcessing::FIRFilter luminance_filter(taps, sampling_rate, 0.0f, cutoff_frequency, SignalProcessing::FIRFilter::DefaultAttenuation); luminance_filter.get_coefficients(coefficients); - int sample = 0; - int c = 0; +// int sample = 0; +// int c = 0; memset(weights, 0, sizeof(float)*12); memset(offsets, 0, sizeof(float)*5); int halfSize = (taps >> 1); - while(c < halfSize && sample < 5) + for(int c = 0; c < taps; c++) { - offsets[sample] = (float)(halfSize - c); - if((coefficients[c] < 0.0f) == (coefficients[c+1] < 0.0f) && c+1 < (taps >> 1)) - { - weights[sample] = coefficients[c] + coefficients[c+1]; - offsets[sample] -= (coefficients[c+1] / weights[sample]); - c += 2; - } - else - { - weights[sample] = coefficients[c]; - c++; - } - sample ++; - } - if(c == halfSize) // i.e. we finished combining inputs before we ran out of space - { - weights[sample] = coefficients[c]; - for(int c = 0; c < sample; c++) - { - weights[sample+c+1] = weights[sample-c-1]; - } - break; + if(c < 5) offsets[c] = (halfSize - c); + weights[c] = coefficients[c]; } + break; + +// int halfSize = (taps >> 1); +// while(c < halfSize && sample < 5) +// { +// offsets[sample] = (float)(halfSize - c); +// if((coefficients[c] < 0.0f) == (coefficients[c+1] < 0.0f) && c+1 < (taps >> 1)) +// { +// weights[sample] = coefficients[c] + coefficients[c+1]; +// offsets[sample] -= (coefficients[c+1] / weights[sample]); +// c += 2; +// } +// else +// { +// weights[sample] = coefficients[c]; +// c++; +// } +// sample ++; +// } +// if(c == halfSize) // i.e. we finished combining inputs before we ran out of space +// { +// weights[sample] = coefficients[c]; +// for(int c = 0; c < sample; c++) +// { +// weights[sample+c+1] = weights[sample-c-1]; +// } +// break; +// } taps -= 2; } diff --git a/Outputs/CRT/Internals/TextureTarget.cpp b/Outputs/CRT/Internals/TextureTarget.cpp index 6a6e5f426..c5d390a12 100644 --- a/Outputs/CRT/Internals/TextureTarget.cpp +++ b/Outputs/CRT/Internals/TextureTarget.cpp @@ -34,7 +34,7 @@ TextureTarget::TextureTarget(GLsizei width, GLsizei height, GLenum texture_unit) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)_expanded_width, (GLsizei)_expanded_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, blank_buffer); free(blank_buffer); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _texture, 0); From c84004bfa3e76b0c66e03df2a8701d6723de9cf2 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 6 Jan 2017 21:36:19 -0500 Subject: [PATCH 06/26] Fixed: colour_cycle_numerator_ doesn't need to be multiplied by the time multiplier because it'll get that for free from the calculation of next_run_length. --- Outputs/CRT/CRT.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Outputs/CRT/CRT.cpp b/Outputs/CRT/CRT.cpp index 8e7694761..5a6b617f1 100644 --- a/Outputs/CRT/CRT.cpp +++ b/Outputs/CRT/CRT.cpp @@ -31,7 +31,7 @@ void CRT::set_new_timing(unsigned int cycles_per_line, unsigned int height_of_di time_multiplier_ = IntermediateBufferWidth / cycles_per_line; phase_denominator_ = cycles_per_line * colour_cycle_denominator; phase_numerator_ = 0; - colour_cycle_numerator_ = colour_cycle_numerator * time_multiplier_; + colour_cycle_numerator_ = colour_cycle_numerator; phase_alternates_ = should_alternate; is_alernate_line_ &= phase_alternates_; unsigned int multiplied_cycles_per_line = cycles_per_line * time_multiplier_; From 5740015f560fd0add5cbf1717dae169d3afa3ac9 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 7 Jan 2017 12:38:00 -0500 Subject: [PATCH 07/26] =?UTF-8?q?Temporarily=20disabled=20composite=20proc?= =?UTF-8?q?essing=20to=20show=20the=20pure=20stream.=20Fixed=20both=20auto?= =?UTF-8?q?matic=20calculations=20of=20phase=20=E2=80=94=20per=20line=20an?= =?UTF-8?q?d,=20at=20input,=20per=20pixel.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Outputs/CRT/CRT.cpp | 2 +- Outputs/CRT/Internals/CRTOpenGL.cpp | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Outputs/CRT/CRT.cpp b/Outputs/CRT/CRT.cpp index 5a6b617f1..76df84488 100644 --- a/Outputs/CRT/CRT.cpp +++ b/Outputs/CRT/CRT.cpp @@ -29,7 +29,7 @@ void CRT::set_new_timing(unsigned int cycles_per_line, unsigned int height_of_di // for horizontal retrace and 500 to 750 µs for vertical retrace in NTSC and PAL TV." time_multiplier_ = IntermediateBufferWidth / cycles_per_line; - phase_denominator_ = cycles_per_line * colour_cycle_denominator; + phase_denominator_ = cycles_per_line * colour_cycle_denominator * time_multiplier_; phase_numerator_ = 0; colour_cycle_numerator_ = colour_cycle_numerator; phase_alternates_ = should_alternate; diff --git a/Outputs/CRT/Internals/CRTOpenGL.cpp b/Outputs/CRT/Internals/CRTOpenGL.cpp index 48bc65d6a..06067ad8a 100644 --- a/Outputs/CRT/Internals/CRTOpenGL.cpp +++ b/Outputs/CRT/Internals/CRTOpenGL.cpp @@ -132,9 +132,9 @@ void OpenGLOutputBuilder::draw_frame(unsigned int output_width, unsigned int out RenderStage composite_render_stages[] = { {&composite_texture_, composite_input_shader_program_.get(), {0.0, 0.0, 0.0}}, - {&separated_texture_, composite_separation_filter_program_.get(), {0.0, 0.5, 0.5}}, - {&filtered_y_texture_, composite_y_filter_shader_program_.get(), {0.0, 0.5, 0.5}}, - {&filtered_texture_, composite_chrominance_filter_shader_program_.get(), {0.0, 0.0, 0.0}}, +// {&separated_texture_, composite_separation_filter_program_.get(), {0.0, 0.5, 0.5}}, +// {&filtered_y_texture_, composite_y_filter_shader_program_.get(), {0.0, 0.5, 0.5}}, +// {&filtered_texture_, composite_chrominance_filter_shader_program_.get(), {0.0, 0.0, 0.0}}, {nullptr} }; @@ -295,7 +295,7 @@ void OpenGLOutputBuilder::prepare_source_vertex_array() void OpenGLOutputBuilder::prepare_output_shader() { output_shader_program_ = OpenGL::OutputShader::make_shader("", "texture(texID, srcCoordinatesVarying).rgb", false); - output_shader_program_->set_source_texture_unit(filtered_texture_unit); + output_shader_program_->set_source_texture_unit(composite_texture_unit);//filtered_texture_unit); } void OpenGLOutputBuilder::prepare_output_vertex_array() @@ -367,6 +367,10 @@ void OpenGLOutputBuilder::set_colour_space_uniforms() void OpenGLOutputBuilder::set_timing_uniforms() { + const float colour_subcarrier_frequency = (float)colour_cycle_numerator_ / (float)colour_cycle_denominator_; + const float output_width = ((float)colour_cycle_numerator_ * 4.0f) / (float)(colour_cycle_denominator_ * IntermediateBufferWidth); + const float sample_cycles_per_line = cycles_per_line_ / output_width; + OpenGL::IntermediateShader *intermediate_shaders[] = { composite_input_shader_program_.get(), composite_separation_filter_program_.get(), @@ -374,17 +378,13 @@ void OpenGLOutputBuilder::set_timing_uniforms() composite_chrominance_filter_shader_program_.get() }; bool extends = false; - float phaseCyclesPerTick = (float)colour_cycle_numerator_ / (float)(colour_cycle_denominator_ * cycles_per_line_); + float phase_cycles_per_tick = 0.25f; for(int c = 0; c < 3; c++) { - if(intermediate_shaders[c]) intermediate_shaders[c]->set_phase_cycles_per_sample(phaseCyclesPerTick, extends); + if(intermediate_shaders[c]) intermediate_shaders[c]->set_phase_cycles_per_sample(phase_cycles_per_tick, extends); extends = true; } - float colour_subcarrier_frequency = (float)colour_cycle_numerator_ / (float)colour_cycle_denominator_; - float output_width = ((float)colour_cycle_numerator_ * 4.0f) / (float)(colour_cycle_denominator_ * IntermediateBufferWidth); - float sample_cycles_per_line = cycles_per_line_ / output_width; - if(composite_separation_filter_program_) { composite_separation_filter_program_->set_width_scalers(output_width, output_width); From 0487b8c17809736787cc7e699f35072b240525dc Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 7 Jan 2017 16:02:33 -0500 Subject: [PATCH 08/26] Definitively eliminated the additional y filtering step; if I'm going to work to ensure always four samples per colour cycle, I can put the channel separation coefficients directly into their shaders, cutting down on samples. --- Outputs/CRT/Internals/CRTOpenGL.cpp | 31 ++-- Outputs/CRT/Internals/CRTOpenGL.hpp | 5 +- .../Internals/Shaders/IntermediateShader.cpp | 134 +++++++----------- .../Internals/Shaders/IntermediateShader.hpp | 5 - 4 files changed, 68 insertions(+), 107 deletions(-) diff --git a/Outputs/CRT/Internals/CRTOpenGL.cpp b/Outputs/CRT/Internals/CRTOpenGL.cpp index 06067ad8a..1bacdb20c 100644 --- a/Outputs/CRT/Internals/CRTOpenGL.cpp +++ b/Outputs/CRT/Internals/CRTOpenGL.cpp @@ -18,10 +18,9 @@ using namespace Outputs::CRT; namespace { static const GLenum composite_texture_unit = GL_TEXTURE0; static const GLenum separated_texture_unit = GL_TEXTURE1; - static const GLenum filtered_y_texture_unit = GL_TEXTURE2; - static const GLenum filtered_texture_unit = GL_TEXTURE3; - static const GLenum source_data_texture_unit = GL_TEXTURE4; - static const GLenum pixel_accumulation_texture_unit = GL_TEXTURE5; + static const GLenum filtered_texture_unit = GL_TEXTURE2; + static const GLenum source_data_texture_unit = GL_TEXTURE3; + static const GLenum pixel_accumulation_texture_unit = GL_TEXTURE4; } OpenGLOutputBuilder::OpenGLOutputBuilder(size_t bytes_per_pixel) : @@ -36,7 +35,6 @@ OpenGLOutputBuilder::OpenGLOutputBuilder(size_t bytes_per_pixel) : array_builder(SourceVertexBufferDataSize, OutputVertexBufferDataSize), composite_texture_(IntermediateBufferWidth, IntermediateBufferHeight, composite_texture_unit), separated_texture_(IntermediateBufferWidth, IntermediateBufferHeight, separated_texture_unit), - filtered_y_texture_(IntermediateBufferWidth, IntermediateBufferHeight, filtered_y_texture_unit), filtered_texture_(IntermediateBufferWidth, IntermediateBufferHeight, filtered_texture_unit) { glBlendFunc(GL_SRC_ALPHA, GL_CONSTANT_COLOR); @@ -132,9 +130,9 @@ void OpenGLOutputBuilder::draw_frame(unsigned int output_width, unsigned int out RenderStage composite_render_stages[] = { {&composite_texture_, composite_input_shader_program_.get(), {0.0, 0.0, 0.0}}, -// {&separated_texture_, composite_separation_filter_program_.get(), {0.0, 0.5, 0.5}}, + {&separated_texture_, composite_separation_filter_program_.get(), {0.0, 0.5, 0.5}}, // {&filtered_y_texture_, composite_y_filter_shader_program_.get(), {0.0, 0.5, 0.5}}, -// {&filtered_texture_, composite_chrominance_filter_shader_program_.get(), {0.0, 0.0, 0.0}}, + {&filtered_texture_, composite_chrominance_filter_shader_program_.get(), {0.0, 0.0, 0.0}}, {nullptr} }; @@ -211,7 +209,6 @@ void OpenGLOutputBuilder::reset_all_OpenGL_state() { composite_input_shader_program_ = nullptr; composite_separation_filter_program_ = nullptr; - composite_y_filter_shader_program_ = nullptr; composite_chrominance_filter_shader_program_ = nullptr; rgb_input_shader_program_ = nullptr; rgb_filter_shader_program_ = nullptr; @@ -255,12 +252,12 @@ void OpenGLOutputBuilder::prepare_composite_input_shaders() composite_separation_filter_program_->set_source_texture_unit(composite_texture_unit); composite_separation_filter_program_->set_output_size(IntermediateBufferWidth, IntermediateBufferHeight); - composite_y_filter_shader_program_ = OpenGL::IntermediateShader::make_luma_filter_shader(); - composite_y_filter_shader_program_->set_source_texture_unit(separated_texture_unit); - composite_y_filter_shader_program_->set_output_size(IntermediateBufferWidth, IntermediateBufferHeight); +// composite_y_filter_shader_program_ = OpenGL::IntermediateShader::make_luma_filter_shader(); +// composite_y_filter_shader_program_->set_source_texture_unit(separated_texture_unit); +// composite_y_filter_shader_program_->set_output_size(IntermediateBufferWidth, IntermediateBufferHeight); composite_chrominance_filter_shader_program_ = OpenGL::IntermediateShader::make_chroma_filter_shader(); - composite_chrominance_filter_shader_program_->set_source_texture_unit(filtered_y_texture_unit); + composite_chrominance_filter_shader_program_->set_source_texture_unit(separated_texture_unit); composite_chrominance_filter_shader_program_->set_output_size(IntermediateBufferWidth, IntermediateBufferHeight); } @@ -295,7 +292,7 @@ void OpenGLOutputBuilder::prepare_source_vertex_array() void OpenGLOutputBuilder::prepare_output_shader() { output_shader_program_ = OpenGL::OutputShader::make_shader("", "texture(texID, srcCoordinatesVarying).rgb", false); - output_shader_program_->set_source_texture_unit(composite_texture_unit);//filtered_texture_unit); + output_shader_program_->set_source_texture_unit(filtered_texture_unit); } void OpenGLOutputBuilder::prepare_output_vertex_array() @@ -362,6 +359,7 @@ void OpenGLOutputBuilder::set_colour_space_uniforms() } if(composite_input_shader_program_) composite_input_shader_program_->set_colour_conversion_matrices(fromRGB, toRGB); + if(composite_separation_filter_program_) composite_separation_filter_program_->set_colour_conversion_matrices(fromRGB, toRGB); if(composite_chrominance_filter_shader_program_) composite_chrominance_filter_shader_program_->set_colour_conversion_matrices(fromRGB, toRGB); } @@ -374,7 +372,6 @@ void OpenGLOutputBuilder::set_timing_uniforms() OpenGL::IntermediateShader *intermediate_shaders[] = { composite_input_shader_program_.get(), composite_separation_filter_program_.get(), - composite_y_filter_shader_program_.get(), composite_chrominance_filter_shader_program_.get() }; bool extends = false; @@ -390,15 +387,9 @@ void OpenGLOutputBuilder::set_timing_uniforms() composite_separation_filter_program_->set_width_scalers(output_width, output_width); composite_separation_filter_program_->set_separation_frequency(sample_cycles_per_line, colour_subcarrier_frequency); } - if(composite_y_filter_shader_program_) - { - composite_y_filter_shader_program_->set_width_scalers(output_width, output_width); - composite_y_filter_shader_program_->set_filter_coefficients(sample_cycles_per_line, colour_subcarrier_frequency); - } if(composite_chrominance_filter_shader_program_) { composite_chrominance_filter_shader_program_->set_width_scalers(output_width, output_width); - composite_chrominance_filter_shader_program_->set_filter_coefficients(sample_cycles_per_line, colour_subcarrier_frequency); } if(rgb_filter_shader_program_) { diff --git a/Outputs/CRT/Internals/CRTOpenGL.hpp b/Outputs/CRT/Internals/CRTOpenGL.hpp index 2c8718eac..c6c19e74d 100644 --- a/Outputs/CRT/Internals/CRTOpenGL.hpp +++ b/Outputs/CRT/Internals/CRTOpenGL.hpp @@ -66,12 +66,11 @@ class OpenGLOutputBuilder { GLsizei composite_src_output_y_; std::unique_ptr output_shader_program_; - std::unique_ptr composite_input_shader_program_, composite_separation_filter_program_, composite_y_filter_shader_program_, composite_chrominance_filter_shader_program_; + std::unique_ptr composite_input_shader_program_, composite_separation_filter_program_, composite_chrominance_filter_shader_program_; std::unique_ptr rgb_input_shader_program_, rgb_filter_shader_program_; OpenGL::TextureTarget composite_texture_; // receives raw composite levels - OpenGL::TextureTarget separated_texture_; // receives unfiltered Y in the R channel plus unfiltered but demodulated chrominance in G and B - OpenGL::TextureTarget filtered_y_texture_; // receives filtered Y in the R channel plus unfiltered chrominance in G and B + OpenGL::TextureTarget separated_texture_; // receives filtered Y in the R channel plus unfiltered but demodulated chrominance in G and B OpenGL::TextureTarget filtered_texture_; // receives filtered YIQ or YUV std::unique_ptr framebuffer_; // the current pixel output diff --git a/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp b/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp index 69eaa8f15..3832fc76f 100644 --- a/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp +++ b/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp @@ -194,35 +194,51 @@ std::unique_ptr IntermediateShader::make_chroma_luma_separat "void main(void)" "{" // grab 11 samples - "vec4 samples[3] = vec4[](" - "vec4(" + "vec3 samples[] = vec3[](" + "vec3(" "texture(texID, inputPositionsVarying[0]).r," - "texture(texID, inputPositionsVarying[1]).r," "texture(texID, inputPositionsVarying[2]).r," "texture(texID, inputPositionsVarying[3]).r" ")," - "vec4(" + "vec3(" "texture(texID, inputPositionsVarying[4]).r," "texture(texID, inputPositionsVarying[5]).r," - "texture(texID, inputPositionsVarying[6]).r," - "texture(texID, inputPositionsVarying[7]).r" + "texture(texID, inputPositionsVarying[6]).r" ")," - "vec4(" + "vec3(" + "texture(texID, inputPositionsVarying[7]).r," "texture(texID, inputPositionsVarying[8]).r," - "texture(texID, inputPositionsVarying[9]).r," - "texture(texID, inputPositionsVarying[10]).r," - "0.0" + "texture(texID, inputPositionsVarying[10]).r" + ")" + ");" + + "vec3 fixedWeights[] = vec3[](" + "vec3(" + "-0.000918," + "0.027278," + "0.103969" + ")," + "vec3(" + "0.202962," + "0.250000," + "0.202962" + ")," + "vec3(" + "0.103969," + "0.027278," + "-0.000918" ")" ");" // apply the low-pass filter to separate luma "float luminance = " "dot(vec3(" - "dot(samples[0], weights[0])," - "dot(samples[1], weights[1])," - "dot(samples[2], weights[2])" + "dot(samples[0], fixedWeights[0])," + "dot(samples[1], fixedWeights[1])," + "dot(samples[2], fixedWeights[2])" "), vec3(1.0));" + // define chroma to be whatever was here, minus luma "float chrominance = 0.5 * (samples[1].y - luminance) / phaseAndAmplitudeVarying.y;" "luminance /= (1.0 - phaseAndAmplitudeVarying.y);" @@ -251,40 +267,47 @@ std::unique_ptr IntermediateShader::make_chroma_filter_shade "{" "vec3 samples[] = vec3[](" "texture(texID, inputPositionsVarying[0]).rgb," - "texture(texID, inputPositionsVarying[1]).rgb," "texture(texID, inputPositionsVarying[2]).rgb," - "texture(texID, inputPositionsVarying[3]).rgb," "texture(texID, inputPositionsVarying[4]).rgb," "texture(texID, inputPositionsVarying[5]).rgb," "texture(texID, inputPositionsVarying[6]).rgb," - "texture(texID, inputPositionsVarying[7]).rgb," "texture(texID, inputPositionsVarying[8]).rgb," - "texture(texID, inputPositionsVarying[9]).rgb," "texture(texID, inputPositionsVarying[10]).rgb" ");" + "vec4 fixedWeights[2] = vec4[](" + "vec4(" + "0.001298," + "-0.038576," + "0.287031," + "0.500000" + ")," + "vec4(" + "0.287031," + "-0.038576," + "0.001298," + "0.0" + ")" + ");" + "vec4 chromaChannel1[] = vec4[](" "vec4(samples[0].g, samples[1].g, samples[2].g, samples[3].g)," - "vec4(samples[4].g, samples[5].g, samples[6].g, samples[7].g)," - "vec4(samples[8].g, samples[9].g, samples[10].g, 0.0)" + "vec4(samples[4].g, samples[5].g, samples[6].g, 0.0)" ");" "vec4 chromaChannel2[] = vec4[](" "vec4(samples[0].b, samples[1].b, samples[2].b, samples[3].b)," - "vec4(samples[4].b, samples[5].b, samples[6].b, samples[7].b)," - "vec4(samples[8].b, samples[9].b, samples[10].b, 0.0)" + "vec4(samples[4].b, samples[5].b, samples[6].b, 0.0)" ");" - "vec3 lumaChromaColour = vec3(samples[5].r," - "dot(vec3(" - "dot(chromaChannel1[0], weights[0])," - "dot(chromaChannel1[1], weights[1])," - "dot(chromaChannel1[2], weights[2])" - "), vec3(1.0))," - "dot(vec3(" - "dot(chromaChannel2[0], weights[0])," - "dot(chromaChannel2[1], weights[1])," - "dot(chromaChannel2[2], weights[2])" - "), vec3(1.0))" + "vec3 lumaChromaColour = vec3(samples[3].r," + "dot(vec2(" + "dot(chromaChannel1[0], fixedWeights[0])," + "dot(chromaChannel1[1], fixedWeights[1])" + "), vec2(1.0))," + "dot(vec2(" + "dot(chromaChannel2[0], fixedWeights[0])," + "dot(chromaChannel2[1], fixedWeights[1])" + "), vec2(1.0))" ");" "vec3 lumaChromaColourInRange = (lumaChromaColour - vec3(0.0, 0.5, 0.5)) * vec3(1.0, 2.0, 2.0);" @@ -292,53 +315,6 @@ std::unique_ptr IntermediateShader::make_chroma_filter_shade "}", false, false); } -std::unique_ptr IntermediateShader::make_luma_filter_shader() -{ - return make_shader( - "#version 150\n" - - "in vec2 inputPositionsVarying[11];" - "uniform vec4 weights[3];" - - "out vec3 fragColour;" - - "uniform sampler2D texID;" - "uniform mat3 lumaChromaToRGB;" - - "void main(void)" - "{" - "vec3 samples[] = vec3[](" - "texture(texID, inputPositionsVarying[0]).rgb," - "texture(texID, inputPositionsVarying[1]).rgb," - "texture(texID, inputPositionsVarying[2]).rgb," - "texture(texID, inputPositionsVarying[3]).rgb," - "texture(texID, inputPositionsVarying[4]).rgb," - "texture(texID, inputPositionsVarying[5]).rgb," - "texture(texID, inputPositionsVarying[6]).rgb," - "texture(texID, inputPositionsVarying[7]).rgb," - "texture(texID, inputPositionsVarying[8]).rgb," - "texture(texID, inputPositionsVarying[9]).rgb," - "texture(texID, inputPositionsVarying[10]).rgb" - ");" - - "vec4 luminance[] = vec4[](" - "vec4(samples[0].r, samples[1].r, samples[2].r, samples[3].r)," - "vec4(samples[4].r, samples[5].r, samples[6].r, samples[7].r)," - "vec4(samples[8].r, samples[9].r, samples[10].r, 0.0)" - ");" - - "fragColour = vec3(" - "dot(vec3(" - "dot(luminance[0], weights[0])," - "dot(luminance[1], weights[1])," - "dot(luminance[2], weights[2])" - "), vec3(1.0))," - "samples[5].gb" - ");" -// "fragColour = texture(texID, inputPositionsVarying[5]).rgb;"//lumaChromaToRGB * lumaChromaColourInRange;" - "}", false, false); -} - std::unique_ptr IntermediateShader::make_rgb_filter_shader() { return make_shader( diff --git a/Outputs/CRT/Internals/Shaders/IntermediateShader.hpp b/Outputs/CRT/Internals/Shaders/IntermediateShader.hpp index 63402fb88..335b52be8 100644 --- a/Outputs/CRT/Internals/Shaders/IntermediateShader.hpp +++ b/Outputs/CRT/Internals/Shaders/IntermediateShader.hpp @@ -44,11 +44,6 @@ public: */ static std::unique_ptr make_chroma_filter_shader(); - /*! - Constructs and returns an intermediate shader that will filter R while passing through G and B unchanged. - */ - static std::unique_ptr make_luma_filter_shader(); - /*! Constructs and returns an intermediate shader that will filter R, G and B. */ From be48c950b484d5743ec13654e006d3f23545a074 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 8 Jan 2017 11:13:20 -0500 Subject: [PATCH 09/26] Started taking steps towards using a texture barrier where possible to reduce all of my framebuffer binds. Some output appears, but it's not correct. --- Outputs/CRT/Internals/CRTOpenGL.cpp | 98 ++++++++++++++----- Outputs/CRT/Internals/CRTOpenGL.hpp | 17 +++- Outputs/CRT/Internals/OpenGL.hpp | 1 + .../Internals/Shaders/IntermediateShader.cpp | 32 +++--- .../Internals/Shaders/IntermediateShader.hpp | 5 + 5 files changed, 109 insertions(+), 44 deletions(-) diff --git a/Outputs/CRT/Internals/CRTOpenGL.cpp b/Outputs/CRT/Internals/CRTOpenGL.cpp index 1bacdb20c..479c73e93 100644 --- a/Outputs/CRT/Internals/CRTOpenGL.cpp +++ b/Outputs/CRT/Internals/CRTOpenGL.cpp @@ -6,8 +6,10 @@ // #include "CRT.hpp" -#include -#include + +#include +#include +#include #include "CRTOpenGL.hpp" #include "../../../SignalProcessing/FIRFilter.hpp" @@ -21,6 +23,8 @@ namespace { static const GLenum filtered_texture_unit = GL_TEXTURE2; static const GLenum source_data_texture_unit = GL_TEXTURE3; static const GLenum pixel_accumulation_texture_unit = GL_TEXTURE4; + + static const GLenum work_texture_unit = GL_TEXTURE0; } OpenGLOutputBuilder::OpenGLOutputBuilder(size_t bytes_per_pixel) : @@ -32,10 +36,7 @@ OpenGLOutputBuilder::OpenGLOutputBuilder(size_t bytes_per_pixel) : last_output_height_(0), fence_(nullptr), texture_builder(bytes_per_pixel, source_data_texture_unit), - array_builder(SourceVertexBufferDataSize, OutputVertexBufferDataSize), - composite_texture_(IntermediateBufferWidth, IntermediateBufferHeight, composite_texture_unit), - separated_texture_(IntermediateBufferWidth, IntermediateBufferHeight, separated_texture_unit), - filtered_texture_(IntermediateBufferWidth, IntermediateBufferHeight, filtered_texture_unit) + array_builder(SourceVertexBufferDataSize, OutputVertexBufferDataSize) { glBlendFunc(GL_SRC_ALPHA, GL_CONSTANT_COLOR); glBlendColor(0.6f, 0.6f, 0.6f, 1.0f); @@ -45,6 +46,32 @@ OpenGLOutputBuilder::OpenGLOutputBuilder(size_t bytes_per_pixel) : // create the source vertex array glGenVertexArrays(1, &source_vertex_array_); + + bool supports_texture_barrier = false; +#ifdef GL_NV_texture_barrier + GLint number_of_extensions; + glGetIntegerv(GL_NUM_EXTENSIONS, &number_of_extensions); + + for(GLuint c = 0; c < (GLuint)number_of_extensions; c++) + { + const char *extension_name = (const char *)glGetStringi(GL_EXTENSIONS, c); + if(!strcmp(extension_name, "GL_NV_texture_barrier")) + { + supports_texture_barrier = true; + } + } +#endif + + if(supports_texture_barrier) + { + work_texture_.reset(new OpenGL::TextureTarget(IntermediateBufferWidth, IntermediateBufferHeight*2, work_texture_unit)); + } + else + { + composite_texture_.reset(new OpenGL::TextureTarget(IntermediateBufferWidth, IntermediateBufferHeight, composite_texture_unit)); + separated_texture_.reset(new OpenGL::TextureTarget(IntermediateBufferWidth, IntermediateBufferHeight, separated_texture_unit)); + filtered_texture_.reset(new OpenGL::TextureTarget(IntermediateBufferWidth, IntermediateBufferHeight, filtered_texture_unit)); + } } OpenGLOutputBuilder::~OpenGLOutputBuilder() @@ -121,26 +148,25 @@ void OpenGLOutputBuilder::draw_frame(unsigned int output_width, unsigned int out output_mutex_.unlock(); struct RenderStage { - OpenGL::TextureTarget *const target; OpenGL::Shader *const shader; + OpenGL::TextureTarget *const target; float clear_colour[3]; }; // for composite video, go through four steps to get to something that can be painted to the output RenderStage composite_render_stages[] = { - {&composite_texture_, composite_input_shader_program_.get(), {0.0, 0.0, 0.0}}, - {&separated_texture_, composite_separation_filter_program_.get(), {0.0, 0.5, 0.5}}, -// {&filtered_y_texture_, composite_y_filter_shader_program_.get(), {0.0, 0.5, 0.5}}, - {&filtered_texture_, composite_chrominance_filter_shader_program_.get(), {0.0, 0.0, 0.0}}, + {composite_input_shader_program_.get(), composite_texture_.get(), {0.0, 0.0, 0.0}}, + {composite_separation_filter_program_.get(), separated_texture_.get(), {0.0, 0.5, 0.5}}, + {composite_chrominance_filter_shader_program_.get(), filtered_texture_.get(), {0.0, 0.0, 0.0}}, {nullptr} }; // for RGB video, there's only two steps RenderStage rgb_render_stages[] = { - {&composite_texture_, rgb_input_shader_program_.get(), {0.0, 0.0, 0.0}}, - {&filtered_texture_, rgb_filter_shader_program_.get(), {0.0, 0.0, 0.0}}, + {rgb_input_shader_program_.get(), composite_texture_.get(), {0.0, 0.0, 0.0}}, + {rgb_filter_shader_program_.get(), filtered_texture_.get(), {0.0, 0.0, 0.0}}, {nullptr} }; @@ -152,24 +178,39 @@ void OpenGLOutputBuilder::draw_frame(unsigned int output_width, unsigned int out glBindVertexArray(source_vertex_array_); glDisable(GL_BLEND); - while(active_pipeline->target) +#ifdef GL_NV_texture_barrier + if(work_texture_) + { + work_texture_->bind_framebuffer(); + glClear(GL_COLOR_BUFFER_BIT); + } +#endif + + while(active_pipeline->shader) { // switch to the framebuffer and shader associated with this stage active_pipeline->shader->bind(); - active_pipeline->target->bind_framebuffer(); - // if this is the final stage before painting to the CRT, clear the framebuffer before drawing in order to blank out - // those portions for which no input was provided - if(!active_pipeline[1].target) + if(!work_texture_) { - glClearColor(active_pipeline->clear_colour[0], active_pipeline->clear_colour[1], active_pipeline->clear_colour[2], 1.0f); - glClear(GL_COLOR_BUFFER_BIT); + active_pipeline->target->bind_framebuffer(); + + // if this is the final stage before painting to the CRT, clear the framebuffer before drawing in order to blank out + // those portions for which no input was provided + if(!active_pipeline[1].shader) + { + glClearColor(active_pipeline->clear_colour[0], active_pipeline->clear_colour[1], active_pipeline->clear_colour[2], 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + } } // draw glDrawArraysInstanced(GL_LINES, 0, 2, (GLsizei)array_submission.input_size / SourceVertexSize); active_pipeline++; +#ifdef GL_NV_texture_barrier + glTextureBarrierNV(); +#endif } // prepare to transfer to framebuffer @@ -192,6 +233,10 @@ void OpenGLOutputBuilder::draw_frame(unsigned int output_width, unsigned int out glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, (GLsizei)array_submission.output_size / OutputVertexSize); } +#ifdef GL_NV_texture_barrier + glTextureBarrierNV(); +#endif + // copy framebuffer to the intended place glDisable(GL_BLEND); glBindFramebuffer(GL_FRAMEBUFFER, 0); @@ -247,18 +292,17 @@ void OpenGLOutputBuilder::prepare_composite_input_shaders() composite_input_shader_program_ = OpenGL::IntermediateShader::make_source_conversion_shader(composite_shader_, rgb_shader_); composite_input_shader_program_->set_source_texture_unit(source_data_texture_unit); composite_input_shader_program_->set_output_size(IntermediateBufferWidth, IntermediateBufferHeight); + composite_input_shader_program_->set_vertical_offsets(0.0f, 0.0f); composite_separation_filter_program_ = OpenGL::IntermediateShader::make_chroma_luma_separation_shader(); - composite_separation_filter_program_->set_source_texture_unit(composite_texture_unit); + composite_separation_filter_program_->set_source_texture_unit(work_texture_ ? work_texture_unit : composite_texture_unit); composite_separation_filter_program_->set_output_size(IntermediateBufferWidth, IntermediateBufferHeight); - -// composite_y_filter_shader_program_ = OpenGL::IntermediateShader::make_luma_filter_shader(); -// composite_y_filter_shader_program_->set_source_texture_unit(separated_texture_unit); -// composite_y_filter_shader_program_->set_output_size(IntermediateBufferWidth, IntermediateBufferHeight); + composite_separation_filter_program_->set_vertical_offsets(0.0f, work_texture_ ? 0.5f : 0.0f); composite_chrominance_filter_shader_program_ = OpenGL::IntermediateShader::make_chroma_filter_shader(); - composite_chrominance_filter_shader_program_->set_source_texture_unit(separated_texture_unit); + composite_chrominance_filter_shader_program_->set_source_texture_unit(work_texture_ ? work_texture_unit : separated_texture_unit); composite_chrominance_filter_shader_program_->set_output_size(IntermediateBufferWidth, IntermediateBufferHeight); + composite_chrominance_filter_shader_program_->set_vertical_offsets(work_texture_ ? 0.5f : 0.0f, 0.0f); } void OpenGLOutputBuilder::prepare_rgb_input_shaders() @@ -292,7 +336,7 @@ void OpenGLOutputBuilder::prepare_source_vertex_array() void OpenGLOutputBuilder::prepare_output_shader() { output_shader_program_ = OpenGL::OutputShader::make_shader("", "texture(texID, srcCoordinatesVarying).rgb", false); - output_shader_program_->set_source_texture_unit(filtered_texture_unit); + output_shader_program_->set_source_texture_unit(work_texture_ ? work_texture_unit : filtered_texture_unit); } void OpenGLOutputBuilder::prepare_output_vertex_array() diff --git a/Outputs/CRT/Internals/CRTOpenGL.hpp b/Outputs/CRT/Internals/CRTOpenGL.hpp index c6c19e74d..551a20193 100644 --- a/Outputs/CRT/Internals/CRTOpenGL.hpp +++ b/Outputs/CRT/Internals/CRTOpenGL.hpp @@ -66,12 +66,19 @@ class OpenGLOutputBuilder { GLsizei composite_src_output_y_; std::unique_ptr output_shader_program_; - std::unique_ptr composite_input_shader_program_, composite_separation_filter_program_, composite_chrominance_filter_shader_program_; - std::unique_ptr rgb_input_shader_program_, rgb_filter_shader_program_; - OpenGL::TextureTarget composite_texture_; // receives raw composite levels - OpenGL::TextureTarget separated_texture_; // receives filtered Y in the R channel plus unfiltered but demodulated chrominance in G and B - OpenGL::TextureTarget filtered_texture_; // receives filtered YIQ or YUV + std::unique_ptr composite_input_shader_program_; + std::unique_ptr composite_separation_filter_program_; + std::unique_ptr composite_chrominance_filter_shader_program_; + + std::unique_ptr rgb_input_shader_program_; + std::unique_ptr rgb_filter_shader_program_; + + std::unique_ptr composite_texture_; // receives raw composite levels + std::unique_ptr separated_texture_; // receives filtered Y in the R channel plus unfiltered but demodulated chrominance in G and B + std::unique_ptr filtered_texture_; // receives filtered YIQ or YUV + + std::unique_ptr work_texture_; // used for all intermediate rendering if texture fences are supported std::unique_ptr framebuffer_; // the current pixel output diff --git a/Outputs/CRT/Internals/OpenGL.hpp b/Outputs/CRT/Internals/OpenGL.hpp index 4d373546b..629ebd501 100644 --- a/Outputs/CRT/Internals/OpenGL.hpp +++ b/Outputs/CRT/Internals/OpenGL.hpp @@ -15,6 +15,7 @@ #else #include #include + #include #endif #endif diff --git a/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp b/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp index 3832fc76f..c85735d21 100644 --- a/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp +++ b/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp @@ -46,6 +46,8 @@ std::unique_ptr IntermediateShader::make_shader(const char * "uniform %s texID;" "uniform float offsets[5];" "uniform vec2 widthScalers;" + "uniform float inputVerticalOffset;" + "uniform float outputVerticalOffset;" "out vec2 phaseAndAmplitudeVarying;" "out vec2 inputPositionsVarying[11];" @@ -60,8 +62,8 @@ std::unique_ptr IntermediateShader::make_shader(const char * // inputPosition.x is either inputStart.x or ends.x, depending on whether it is on the left or the right; // outputPosition.x is either outputStart.x or ends.y; // .ys are inputStart.y and outputStart.y respectively - "vec2 inputPosition = vec2(mix(inputStart.x, ends.x, extent)*widthScalers[0], inputStart.y);" - "vec2 outputPosition = vec2(mix(outputStart.x, ends.y, extent)*widthScalers[1], outputStart.y);" + "vec2 inputPosition = vec2(mix(inputStart.x, ends.x, extent)*widthScalers[0], inputStart.y + inputVerticalOffset);" + "vec2 outputPosition = vec2(mix(outputStart.x, ends.y, extent)*widthScalers[1], outputStart.y + outputVerticalOffset);" // extension is the amount to extend both the input and output by to add a full colour cycle at each end "vec2 extensionVector = vec2(extension, 0.0) * 2.0 * (extent - 0.5);" @@ -76,17 +78,17 @@ std::unique_ptr IntermediateShader::make_shader(const char * "vec2 mappedInputPosition = (extendedInputPosition + vec2(0.0, 0.5)) / textureSize;" // setup input positions spaced as per the supplied offsets; these are for filtering where required - "inputPositionsVarying[0] = mappedInputPosition - (vec2(offsets[0], 0.0) / textureSize);" - "inputPositionsVarying[1] = mappedInputPosition - (vec2(offsets[1], 0.0) / textureSize);" - "inputPositionsVarying[2] = mappedInputPosition - (vec2(offsets[2], 0.0) / textureSize);" - "inputPositionsVarying[3] = mappedInputPosition - (vec2(offsets[3], 0.0) / textureSize);" - "inputPositionsVarying[4] = mappedInputPosition - (vec2(offsets[4], 0.0) / textureSize);" + "inputPositionsVarying[0] = mappedInputPosition - (vec2(5.0, 0.0) / textureSize);" + "inputPositionsVarying[1] = mappedInputPosition - (vec2(4.0, 0.0) / textureSize);" + "inputPositionsVarying[2] = mappedInputPosition - (vec2(3.0, 0.0) / textureSize);" + "inputPositionsVarying[3] = mappedInputPosition - (vec2(2.0, 0.0) / textureSize);" + "inputPositionsVarying[4] = mappedInputPosition - (vec2(1.0, 0.0) / textureSize);" "inputPositionsVarying[5] = mappedInputPosition;" - "inputPositionsVarying[6] = mappedInputPosition + (vec2(offsets[4], 0.0) / textureSize);" - "inputPositionsVarying[7] = mappedInputPosition + (vec2(offsets[3], 0.0) / textureSize);" - "inputPositionsVarying[8] = mappedInputPosition + (vec2(offsets[2], 0.0) / textureSize);" - "inputPositionsVarying[9] = mappedInputPosition + (vec2(offsets[1], 0.0) / textureSize);" - "inputPositionsVarying[10] = mappedInputPosition + (vec2(offsets[0], 0.0) / textureSize);" + "inputPositionsVarying[6] = mappedInputPosition + (vec2(1.0, 0.0) / textureSize);" + "inputPositionsVarying[7] = mappedInputPosition + (vec2(2.0, 0.0) / textureSize);" + "inputPositionsVarying[8] = mappedInputPosition + (vec2(3.0, 0.0) / textureSize);" + "inputPositionsVarying[9] = mappedInputPosition + (vec2(4.0, 0.0) / textureSize);" + "inputPositionsVarying[10] = mappedInputPosition + (vec2(5.0, 0.0) / textureSize);" "delayLinePositionVarying = mappedInputPosition - vec2(0.0, 1.0);" // setup phaseAndAmplitudeVarying.x as colour burst subcarrier phase, in radians; @@ -474,3 +476,9 @@ void IntermediateShader::set_width_scalers(float input_scaler, float output_scal { set_uniform("widthScalers", input_scaler, output_scaler); } + +void IntermediateShader::set_vertical_offsets(float input, float output) +{ + set_uniform("inputVerticalOffset", input); + set_uniform("outputVerticalOffset", output); +} diff --git a/Outputs/CRT/Internals/Shaders/IntermediateShader.hpp b/Outputs/CRT/Internals/Shaders/IntermediateShader.hpp index 335b52be8..c8c801809 100644 --- a/Outputs/CRT/Internals/Shaders/IntermediateShader.hpp +++ b/Outputs/CRT/Internals/Shaders/IntermediateShader.hpp @@ -89,6 +89,11 @@ public: */ void set_width_scalers(float input_scaler, float output_scaler); + /*! + Sets source and target vertical offsets. + */ + void set_vertical_offsets(float input, float output); + private: static std::unique_ptr make_shader(const char *fragment_shader, bool use_usampler, bool input_is_inputPosition); }; From 6153ada33b197773a4199c87eee10dbca4d5f194 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 8 Jan 2017 14:46:19 -0500 Subject: [PATCH 10/26] Fixed Electron's support for automatically booting floppy disks. --- Machines/Electron/Electron.cpp | 17 ++++++++++++++--- Machines/Electron/Electron.hpp | 1 + StaticAnalyser/Acorn/StaticAnalyser.cpp | 19 +++++-------------- StaticAnalyser/StaticAnalyser.hpp | 2 +- 4 files changed, 21 insertions(+), 18 deletions(-) diff --git a/Machines/Electron/Electron.cpp b/Machines/Electron/Electron.cpp index 6052d48d0..b35ba4354 100644 --- a/Machines/Electron/Electron.cpp +++ b/Machines/Electron/Electron.cpp @@ -61,6 +61,7 @@ std::shared_ptr Machine::get_speaker() void Machine::clear_all_keys() { memset(key_states_, 0, sizeof(key_states_)); + if(is_holding_shift_) set_key_state(KeyShift, true); } void Machine::set_key_state(uint16_t key, bool isPressed) @@ -116,10 +117,9 @@ void Machine::configure_as_target(const StaticAnalyser::Target &target) set_typer_for_string(target.loadingCommand.c_str()); } - if(target.acorn.should_hold_shift) + if(target.acorn.should_shift_restart) { - set_key_state(KeyShift, true); - is_holding_shift_ = true; + shift_restart_counter_ = 1000000; } } @@ -398,6 +398,17 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin if(typer_) typer_->update((int)cycles); if(plus3_) plus3_->run_for_cycles(4*cycles); + if(shift_restart_counter_) + { + shift_restart_counter_ -= cycles; + if(shift_restart_counter_ <= 0) + { + shift_restart_counter_ = 0; + set_power_on(true); + set_key_state(KeyShift, true); + is_holding_shift_ = true; + } + } return cycles; } diff --git a/Machines/Electron/Electron.hpp b/Machines/Electron/Electron.hpp index 543d6abcc..bb9588f52 100644 --- a/Machines/Electron/Electron.hpp +++ b/Machines/Electron/Electron.hpp @@ -144,6 +144,7 @@ class Machine: // Disk std::unique_ptr plus3_; bool is_holding_shift_; + int shift_restart_counter_; // Outputs std::unique_ptr video_output_; diff --git a/StaticAnalyser/Acorn/StaticAnalyser.cpp b/StaticAnalyser/Acorn/StaticAnalyser.cpp index 50a5ad478..6a1e2be7a 100644 --- a/StaticAnalyser/Acorn/StaticAnalyser.cpp +++ b/StaticAnalyser/Acorn/StaticAnalyser.cpp @@ -69,7 +69,7 @@ void StaticAnalyser::Acorn::AddTargets( target.probability = 1.0; // TODO: a proper estimation target.acorn.has_dfs = false; target.acorn.has_adfs = false; - target.acorn.should_hold_shift = false; + target.acorn.should_shift_restart = false; // strip out inappropriate cartridges target.cartridges = AcornCartridgesFrom(cartridges); @@ -126,20 +126,11 @@ void StaticAnalyser::Acorn::AddTargets( target.acorn.has_dfs = !!dfs_catalogue; target.acorn.has_adfs = !!adfs_catalogue; - std::string adfs_command; Catalogue::BootOption bootOption = (dfs_catalogue ?: adfs_catalogue)->bootOption; - switch(bootOption) - { - case Catalogue::BootOption::None: adfs_command = "*CAT\n"; break; - case Catalogue::BootOption::LoadBOOT: adfs_command = "*LOAD !BOOT\n"; break; - case Catalogue::BootOption::RunBOOT: adfs_command = "*RUN !BOOT\n"; break; - case Catalogue::BootOption::ExecBOOT: adfs_command = "*EXEC !BOOT\n"; break; - } - -// if(target.acorn.has_dfs && bootOption != Catalogue::BootOption::None) -// target.acorn.should_hold_shift = true; -// else - target.loadingCommand = (target.acorn.has_dfs ? "" : "*MOUNT\n") + adfs_command; + if(bootOption != Catalogue::BootOption::None) + target.acorn.should_shift_restart = true; + else + target.loadingCommand = "*CAT\n"; } } diff --git a/StaticAnalyser/StaticAnalyser.hpp b/StaticAnalyser/StaticAnalyser.hpp index 6a2d2e0e3..ffef83a23 100644 --- a/StaticAnalyser/StaticAnalyser.hpp +++ b/StaticAnalyser/StaticAnalyser.hpp @@ -47,7 +47,7 @@ struct Target { struct { bool has_adfs; bool has_dfs; - bool should_hold_shift; + bool should_shift_restart; } acorn; struct { From 7ad64ff16b702f77c554be23ee2156f65c9f32c0 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 8 Jan 2017 14:47:16 -0500 Subject: [PATCH 11/26] Made further efforts to support throughput via memory barrier. --- Outputs/CRT/Internals/CRTOpenGL.cpp | 40 ++++++++++++------- .../Internals/Shaders/IntermediateShader.cpp | 8 ++-- .../Internals/Shaders/IntermediateShader.hpp | 2 +- .../CRT/Internals/Shaders/OutputShader.cpp | 9 ++++- .../CRT/Internals/Shaders/OutputShader.hpp | 4 ++ 5 files changed, 44 insertions(+), 19 deletions(-) diff --git a/Outputs/CRT/Internals/CRTOpenGL.cpp b/Outputs/CRT/Internals/CRTOpenGL.cpp index 479c73e93..e388c6453 100644 --- a/Outputs/CRT/Internals/CRTOpenGL.cpp +++ b/Outputs/CRT/Internals/CRTOpenGL.cpp @@ -18,13 +18,14 @@ using namespace Outputs::CRT; namespace { - static const GLenum composite_texture_unit = GL_TEXTURE0; - static const GLenum separated_texture_unit = GL_TEXTURE1; - static const GLenum filtered_texture_unit = GL_TEXTURE2; - static const GLenum source_data_texture_unit = GL_TEXTURE3; - static const GLenum pixel_accumulation_texture_unit = GL_TEXTURE4; + static const GLenum source_data_texture_unit = GL_TEXTURE0; + static const GLenum pixel_accumulation_texture_unit = GL_TEXTURE1; - static const GLenum work_texture_unit = GL_TEXTURE0; + static const GLenum composite_texture_unit = GL_TEXTURE2; + static const GLenum separated_texture_unit = GL_TEXTURE3; + static const GLenum filtered_texture_unit = GL_TEXTURE4; + + static const GLenum work_texture_unit = GL_TEXTURE2; } OpenGLOutputBuilder::OpenGLOutputBuilder(size_t bytes_per_pixel) : @@ -62,11 +63,11 @@ OpenGLOutputBuilder::OpenGLOutputBuilder(size_t bytes_per_pixel) : } #endif - if(supports_texture_barrier) - { - work_texture_.reset(new OpenGL::TextureTarget(IntermediateBufferWidth, IntermediateBufferHeight*2, work_texture_unit)); - } - else +// if(supports_texture_barrier) +// { +// work_texture_.reset(new OpenGL::TextureTarget(IntermediateBufferWidth, IntermediateBufferHeight*2, work_texture_unit)); +// } +// else { composite_texture_.reset(new OpenGL::TextureTarget(IntermediateBufferWidth, IntermediateBufferHeight, composite_texture_unit)); separated_texture_.reset(new OpenGL::TextureTarget(IntermediateBufferWidth, IntermediateBufferHeight, separated_texture_unit)); @@ -292,17 +293,27 @@ void OpenGLOutputBuilder::prepare_composite_input_shaders() composite_input_shader_program_ = OpenGL::IntermediateShader::make_source_conversion_shader(composite_shader_, rgb_shader_); composite_input_shader_program_->set_source_texture_unit(source_data_texture_unit); composite_input_shader_program_->set_output_size(IntermediateBufferWidth, IntermediateBufferHeight); - composite_input_shader_program_->set_vertical_offsets(0.0f, 0.0f); composite_separation_filter_program_ = OpenGL::IntermediateShader::make_chroma_luma_separation_shader(); composite_separation_filter_program_->set_source_texture_unit(work_texture_ ? work_texture_unit : composite_texture_unit); composite_separation_filter_program_->set_output_size(IntermediateBufferWidth, IntermediateBufferHeight); - composite_separation_filter_program_->set_vertical_offsets(0.0f, work_texture_ ? 0.5f : 0.0f); composite_chrominance_filter_shader_program_ = OpenGL::IntermediateShader::make_chroma_filter_shader(); composite_chrominance_filter_shader_program_->set_source_texture_unit(work_texture_ ? work_texture_unit : separated_texture_unit); composite_chrominance_filter_shader_program_->set_output_size(IntermediateBufferWidth, IntermediateBufferHeight); - composite_chrominance_filter_shader_program_->set_vertical_offsets(work_texture_ ? 0.5f : 0.0f, 0.0f); + + if(work_texture_) + { + composite_input_shader_program_->set_is_double_height(true, 0.0f, 0.0f); + composite_separation_filter_program_->set_is_double_height(true, 0.0f, 0.5f); + composite_chrominance_filter_shader_program_->set_is_double_height(true, 0.5f, 0.0f); + } + else + { + composite_input_shader_program_->set_is_double_height(false); + composite_separation_filter_program_->set_is_double_height(false); + composite_chrominance_filter_shader_program_->set_is_double_height(false); + } } void OpenGLOutputBuilder::prepare_rgb_input_shaders() @@ -337,6 +348,7 @@ void OpenGLOutputBuilder::prepare_output_shader() { output_shader_program_ = OpenGL::OutputShader::make_shader("", "texture(texID, srcCoordinatesVarying).rgb", false); output_shader_program_->set_source_texture_unit(work_texture_ ? work_texture_unit : filtered_texture_unit); + output_shader_program_->set_origin_is_double_height(!!work_texture_); } void OpenGLOutputBuilder::prepare_output_vertex_array() diff --git a/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp b/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp index c85735d21..06c1fa052 100644 --- a/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp +++ b/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp @@ -48,6 +48,7 @@ std::unique_ptr IntermediateShader::make_shader(const char * "uniform vec2 widthScalers;" "uniform float inputVerticalOffset;" "uniform float outputVerticalOffset;" + "uniform float textureHeightDivisor;" "out vec2 phaseAndAmplitudeVarying;" "out vec2 inputPositionsVarying[11];" @@ -477,8 +478,9 @@ void IntermediateShader::set_width_scalers(float input_scaler, float output_scal set_uniform("widthScalers", input_scaler, output_scaler); } -void IntermediateShader::set_vertical_offsets(float input, float output) +void IntermediateShader::set_is_double_height(bool is_double_height, float input_offset, float output_offset) { - set_uniform("inputVerticalOffset", input); - set_uniform("outputVerticalOffset", output); + set_uniform("textureHeightDivisor", is_double_height ? 2.0f : 1.0f); + set_uniform("inputVerticalOffset", input_offset); + set_uniform("outputVerticalOffset", output_offset); } diff --git a/Outputs/CRT/Internals/Shaders/IntermediateShader.hpp b/Outputs/CRT/Internals/Shaders/IntermediateShader.hpp index c8c801809..046e3bb69 100644 --- a/Outputs/CRT/Internals/Shaders/IntermediateShader.hpp +++ b/Outputs/CRT/Internals/Shaders/IntermediateShader.hpp @@ -92,7 +92,7 @@ public: /*! Sets source and target vertical offsets. */ - void set_vertical_offsets(float input, float output); + void set_is_double_height(bool is_double_height, float input_offset = 0.0f, float output_offset = 0.0f); private: static std::unique_ptr make_shader(const char *fragment_shader, bool use_usampler, bool input_is_inputPosition); diff --git a/Outputs/CRT/Internals/Shaders/OutputShader.cpp b/Outputs/CRT/Internals/Shaders/OutputShader.cpp index 86f0f928c..ea31acebd 100644 --- a/Outputs/CRT/Internals/Shaders/OutputShader.cpp +++ b/Outputs/CRT/Internals/Shaders/OutputShader.cpp @@ -39,6 +39,7 @@ std::unique_ptr OutputShader::make_shader(const char *fragment_met "uniform vec2 scanNormal;" "uniform %s texID;" "uniform float inputScaler;" + "uniform int textureHeightDivisor;" "out float lateralVarying;" "out vec2 srcCoordinatesVarying;" @@ -53,9 +54,10 @@ std::unique_ptr OutputShader::make_shader(const char *fragment_met "lateralVarying = lateral - 0.5;" "vec2 vSrcCoordinates = vec2(x, vertical.y);" - "ivec2 textureSize = textureSize(texID, 0);" + "ivec2 textureSize = textureSize(texID, 0) * ivec2(1, textureHeightDivisor);" "iSrcCoordinatesVarying = vSrcCoordinates;" "srcCoordinatesVarying = vec2(inputScaler * vSrcCoordinates.x / textureSize.x, (vSrcCoordinates.y + 0.5) / textureSize.y);" + "srcCoordinatesVarying.x = srcCoordinatesVarying.x - mod(srcCoordinatesVarying.x, 1.0 / textureSize.x);" "vec2 vPosition = vec2(x, vertical.x);" "vec2 floatingPosition = (vPosition / positionConversion) + lateral * scanNormal;" @@ -123,3 +125,8 @@ void OutputShader::set_input_width_scaler(float input_scaler) { set_uniform("inputScaler", input_scaler); } + +void OutputShader::set_origin_is_double_height(bool is_double_height) +{ + set_uniform("textureHeightDivisor", is_double_height ? 2 : 1); +} diff --git a/Outputs/CRT/Internals/Shaders/OutputShader.hpp b/Outputs/CRT/Internals/Shaders/OutputShader.hpp index 44f4ec041..0df8143f4 100644 --- a/Outputs/CRT/Internals/Shaders/OutputShader.hpp +++ b/Outputs/CRT/Internals/Shaders/OutputShader.hpp @@ -59,6 +59,10 @@ public: */ void set_timing(unsigned int height_of_display, unsigned int cycles_per_line, unsigned int horizontal_scan_period, unsigned int vertical_scan_period, unsigned int vertical_period_divider); + /*! + */ + void set_origin_is_double_height(bool is_double_height); + /*! 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. From 79632b1d34cc1a405be6b3b3a787b8312a0d39f8 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 8 Jan 2017 16:24:22 -0500 Subject: [PATCH 12/26] Instituted de-escalating phase-related extensions, definitively to kill rounding error edges. --- Outputs/CRT/Internals/CRTOpenGL.cpp | 16 +++------------- .../CRT/Internals/Shaders/IntermediateShader.cpp | 4 ++-- .../CRT/Internals/Shaders/IntermediateShader.hpp | 2 +- 3 files changed, 6 insertions(+), 16 deletions(-) diff --git a/Outputs/CRT/Internals/CRTOpenGL.cpp b/Outputs/CRT/Internals/CRTOpenGL.cpp index e388c6453..d9734646f 100644 --- a/Outputs/CRT/Internals/CRTOpenGL.cpp +++ b/Outputs/CRT/Internals/CRTOpenGL.cpp @@ -425,27 +425,16 @@ void OpenGLOutputBuilder::set_timing_uniforms() const float output_width = ((float)colour_cycle_numerator_ * 4.0f) / (float)(colour_cycle_denominator_ * IntermediateBufferWidth); const float sample_cycles_per_line = cycles_per_line_ / output_width; - OpenGL::IntermediateShader *intermediate_shaders[] = { - composite_input_shader_program_.get(), - composite_separation_filter_program_.get(), - composite_chrominance_filter_shader_program_.get() - }; - bool extends = false; - float phase_cycles_per_tick = 0.25f; - for(int c = 0; c < 3; c++) - { - if(intermediate_shaders[c]) intermediate_shaders[c]->set_phase_cycles_per_sample(phase_cycles_per_tick, extends); - extends = true; - } - if(composite_separation_filter_program_) { composite_separation_filter_program_->set_width_scalers(output_width, output_width); composite_separation_filter_program_->set_separation_frequency(sample_cycles_per_line, colour_subcarrier_frequency); + composite_separation_filter_program_->set_phase_cycles_per_sample(0.25f, 6.0f); } if(composite_chrominance_filter_shader_program_) { composite_chrominance_filter_shader_program_->set_width_scalers(output_width, output_width); + composite_chrominance_filter_shader_program_->set_phase_cycles_per_sample(0.25f, 5.0f); } if(rgb_filter_shader_program_) { @@ -460,6 +449,7 @@ void OpenGLOutputBuilder::set_timing_uniforms() if(composite_input_shader_program_) { composite_input_shader_program_->set_width_scalers(1.0f, output_width); + composite_input_shader_program_->set_phase_cycles_per_sample(0.25f, 0.0f); } if(rgb_input_shader_program_) { diff --git a/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp b/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp index 06c1fa052..ebda43d6d 100644 --- a/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp +++ b/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp @@ -461,10 +461,10 @@ void IntermediateShader::set_separation_frequency(float sampling_rate, float col set_filter_coefficients(sampling_rate, colour_burst_frequency); } -void IntermediateShader::set_phase_cycles_per_sample(float phase_cycles_per_sample, bool extend_runs_to_full_cycle) +void IntermediateShader::set_phase_cycles_per_sample(float phase_cycles_per_sample, float extension) { set_uniform("phaseCyclesPerTick", (GLfloat)phase_cycles_per_sample); - set_uniform("extension", extend_runs_to_full_cycle ? ceilf(1.0f / phase_cycles_per_sample) : 0.0f); + set_uniform("extension", extension); } void IntermediateShader::set_colour_conversion_matrices(float *fromRGB, float *toRGB) diff --git a/Outputs/CRT/Internals/Shaders/IntermediateShader.hpp b/Outputs/CRT/Internals/Shaders/IntermediateShader.hpp index 046e3bb69..08a3c6e89 100644 --- a/Outputs/CRT/Internals/Shaders/IntermediateShader.hpp +++ b/Outputs/CRT/Internals/Shaders/IntermediateShader.hpp @@ -76,7 +76,7 @@ public: geometry should be extended so that a complete colour cycle is included at both the beginning and end, to occur upon the next `bind`. */ - void set_phase_cycles_per_sample(float phase_cycles_per_sample, bool extend_runs_to_full_cycle); + void set_phase_cycles_per_sample(float phase_cycles_per_sample, float extension); /*! Queues setting the matrices that convert between RGB and chrominance/luminance to occur on the next `bind`. From 28909e33cad1a80f39dbd10cd915752532a495ac Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 8 Jan 2017 16:48:02 -0500 Subject: [PATCH 13/26] Eliminated phaseCyclesPerTick as implied. --- Outputs/CRT/Internals/CRTOpenGL.cpp | 6 +++--- Outputs/CRT/Internals/Shaders/IntermediateShader.cpp | 6 ++---- Outputs/CRT/Internals/Shaders/IntermediateShader.hpp | 2 +- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/Outputs/CRT/Internals/CRTOpenGL.cpp b/Outputs/CRT/Internals/CRTOpenGL.cpp index d9734646f..55c2a0053 100644 --- a/Outputs/CRT/Internals/CRTOpenGL.cpp +++ b/Outputs/CRT/Internals/CRTOpenGL.cpp @@ -429,12 +429,12 @@ void OpenGLOutputBuilder::set_timing_uniforms() { composite_separation_filter_program_->set_width_scalers(output_width, output_width); composite_separation_filter_program_->set_separation_frequency(sample_cycles_per_line, colour_subcarrier_frequency); - composite_separation_filter_program_->set_phase_cycles_per_sample(0.25f, 6.0f); + composite_separation_filter_program_->set_extension(6.0f); } if(composite_chrominance_filter_shader_program_) { composite_chrominance_filter_shader_program_->set_width_scalers(output_width, output_width); - composite_chrominance_filter_shader_program_->set_phase_cycles_per_sample(0.25f, 5.0f); + composite_chrominance_filter_shader_program_->set_extension(5.0f); } if(rgb_filter_shader_program_) { @@ -449,7 +449,7 @@ void OpenGLOutputBuilder::set_timing_uniforms() if(composite_input_shader_program_) { composite_input_shader_program_->set_width_scalers(1.0f, output_width); - composite_input_shader_program_->set_phase_cycles_per_sample(0.25f, 0.0f); + composite_input_shader_program_->set_extension(0.0f); } if(rgb_input_shader_program_) { diff --git a/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp b/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp index ebda43d6d..cbc7dbbb1 100644 --- a/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp +++ b/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp @@ -40,7 +40,6 @@ std::unique_ptr IntermediateShader::make_shader(const char * "in vec2 ends;" "in vec3 phaseTimeAndAmplitude;" - "uniform float phaseCyclesPerTick;" "uniform ivec2 outputTextureSize;" "uniform float extension;" "uniform %s texID;" @@ -94,7 +93,7 @@ std::unique_ptr IntermediateShader::make_shader(const char * // setup phaseAndAmplitudeVarying.x as colour burst subcarrier phase, in radians; // setup phaseAndAmplitudeVarying.x as colour burst amplitude - "phaseAndAmplitudeVarying.x = (phaseCyclesPerTick * (extendedOutputPosition.x - phaseTimeAndAmplitude.y) + (phaseTimeAndAmplitude.x / 256.0)) * 2.0 * 3.141592654;" + "phaseAndAmplitudeVarying.x = (((extendedOutputPosition.x - phaseTimeAndAmplitude.y) / 4.0) + (phaseTimeAndAmplitude.x / 256.0)) * 2.0 * 3.141592654;" "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 @@ -461,9 +460,8 @@ void IntermediateShader::set_separation_frequency(float sampling_rate, float col set_filter_coefficients(sampling_rate, colour_burst_frequency); } -void IntermediateShader::set_phase_cycles_per_sample(float phase_cycles_per_sample, float extension) +void IntermediateShader::set_extension(float extension) { - set_uniform("phaseCyclesPerTick", (GLfloat)phase_cycles_per_sample); set_uniform("extension", extension); } diff --git a/Outputs/CRT/Internals/Shaders/IntermediateShader.hpp b/Outputs/CRT/Internals/Shaders/IntermediateShader.hpp index 08a3c6e89..13dedc2c4 100644 --- a/Outputs/CRT/Internals/Shaders/IntermediateShader.hpp +++ b/Outputs/CRT/Internals/Shaders/IntermediateShader.hpp @@ -76,7 +76,7 @@ public: geometry should be extended so that a complete colour cycle is included at both the beginning and end, to occur upon the next `bind`. */ - void set_phase_cycles_per_sample(float phase_cycles_per_sample, float extension); + void set_extension(float extension); /*! Queues setting the matrices that convert between RGB and chrominance/luminance to occur on the next `bind`. From 95217181202921e9bf33acb76dea869d2605ea40 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 8 Jan 2017 17:21:26 -0500 Subject: [PATCH 14/26] Colour phase is multiplied by 255, not 256. --- 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 cbc7dbbb1..4325ae7b7 100644 --- a/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp +++ b/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp @@ -93,7 +93,7 @@ std::unique_ptr IntermediateShader::make_shader(const char * // setup phaseAndAmplitudeVarying.x as colour burst subcarrier phase, in radians; // setup phaseAndAmplitudeVarying.x as colour burst amplitude - "phaseAndAmplitudeVarying.x = (((extendedOutputPosition.x - phaseTimeAndAmplitude.y) / 4.0) + (phaseTimeAndAmplitude.x / 256.0)) * 2.0 * 3.141592654;" + "phaseAndAmplitudeVarying.x = (((extendedOutputPosition.x - phaseTimeAndAmplitude.y) / 4.0) + (phaseTimeAndAmplitude.x / 255.0)) * 2.0 * 3.141592654;" "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 From d2a7d39749981d3b236750b37ed02d13b3bade12 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 8 Jan 2017 19:49:21 -0500 Subject: [PATCH 15/26] Ensured the output lock isn't held while talking to the delegate. --- Outputs/CRT/CRT.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Outputs/CRT/CRT.cpp b/Outputs/CRT/CRT.cpp index 76df84488..631e99d6d 100644 --- a/Outputs/CRT/CRT.cpp +++ b/Outputs/CRT/CRT.cpp @@ -242,7 +242,9 @@ void CRT::advance_cycles(unsigned int number_of_cycles, bool hsync_requested, bo frames_since_last_delegate_call_++; if(frames_since_last_delegate_call_ == 20) { + output_lock.unlock(); delegate_->crt_did_end_batch_of_frames(this, frames_since_last_delegate_call_, vertical_flywheel_->get_and_reset_number_of_surprises()); + output_lock.lock(); frames_since_last_delegate_call_ = 0; } } From 3d789732a2b31cf6707f716453d01fa7b0cd3be5 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 8 Jan 2017 19:50:31 -0500 Subject: [PATCH 16/26] Switched back to full buffer clearing. Until I can figure out the source of noise. --- Outputs/CRT/Internals/CRTOpenGL.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/Outputs/CRT/Internals/CRTOpenGL.cpp b/Outputs/CRT/Internals/CRTOpenGL.cpp index 55c2a0053..7282b771a 100644 --- a/Outputs/CRT/Internals/CRTOpenGL.cpp +++ b/Outputs/CRT/Internals/CRTOpenGL.cpp @@ -198,11 +198,11 @@ void OpenGLOutputBuilder::draw_frame(unsigned int output_width, unsigned int out // if this is the final stage before painting to the CRT, clear the framebuffer before drawing in order to blank out // those portions for which no input was provided - if(!active_pipeline[1].shader) - { +// if(!active_pipeline[1].shader) +// { glClearColor(active_pipeline->clear_colour[0], active_pipeline->clear_colour[1], active_pipeline->clear_colour[2], 1.0f); glClear(GL_COLOR_BUFFER_BIT); - } +// } } // draw @@ -272,18 +272,16 @@ void OpenGLOutputBuilder::set_openGL_context_will_change(bool should_delete_reso void OpenGLOutputBuilder::set_composite_sampling_function(const char *shader) { - output_mutex_.lock(); + std::lock_guard lock_guard(output_mutex_); composite_shader_ = strdup(shader); reset_all_OpenGL_state(); - output_mutex_.unlock(); } void OpenGLOutputBuilder::set_rgb_sampling_function(const char *shader) { - output_mutex_.lock(); + std::lock_guard lock_guard(output_mutex_); rgb_shader_ = strdup(shader); reset_all_OpenGL_state(); - output_mutex_.unlock(); } #pragma mark - Program compilation From eeb646868b02877e3e4cea580f4ae8d76cb33a9a Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 8 Jan 2017 19:53:08 -0500 Subject: [PATCH 17/26] Switched off filtering, at least temporarily, to try to ensure that sampling is all where it should be. --- Outputs/CRT/Internals/TextureTarget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Outputs/CRT/Internals/TextureTarget.cpp b/Outputs/CRT/Internals/TextureTarget.cpp index c5d390a12..dccca91f7 100644 --- a/Outputs/CRT/Internals/TextureTarget.cpp +++ b/Outputs/CRT/Internals/TextureTarget.cpp @@ -33,7 +33,7 @@ TextureTarget::TextureTarget(GLsizei width, GLsizei height, GLenum texture_unit) uint8_t *blank_buffer = (uint8_t *)calloc((size_t)(_expanded_width * _expanded_height), 4); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)_expanded_width, (GLsizei)_expanded_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, blank_buffer); free(blank_buffer); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _texture, 0); From 4c3669f21032a35c437b2b83cdef8f7cbef0c4b2 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 10 Jan 2017 22:08:07 -0500 Subject: [PATCH 18/26] Reduced precision of input phase, but I'm not necessarily persuaded by it as a move. However it's clear that something is off in that whole area. But if phase is locked by output position, do I need to retain this level of complexity? Also ensured that intermediate buffers prior to the final are sampled using the nearest sampling mode, also to reduce precision errors. --- Outputs/CRT/CRT.cpp | 2 +- Outputs/CRT/Internals/CRTOpenGL.cpp | 9 +- .../Internals/Shaders/IntermediateShader.cpp | 102 +++--------------- Outputs/CRT/Internals/TextureTarget.cpp | 4 +- Outputs/CRT/Internals/TextureTarget.hpp | 2 +- 5 files changed, 26 insertions(+), 93 deletions(-) diff --git a/Outputs/CRT/CRT.cpp b/Outputs/CRT/CRT.cpp index 631e99d6d..db55f4f63 100644 --- a/Outputs/CRT/CRT.cpp +++ b/Outputs/CRT/CRT.cpp @@ -147,7 +147,7 @@ void CRT::advance_cycles(unsigned int number_of_cycles, bool hsync_requested, bo { // output_y and texture locations will be written later; we won't necessarily know what it is outside of the locked region source_output_position_x1() = (uint16_t)horizontal_flywheel_->get_current_output_position(); - source_phase() = colour_burst_phase_; + source_phase() = 31 + colour_burst_phase_ & ~63; // phase is rounded to the nearest 1/4 of a cycle source_amplitude() = colour_burst_amplitude_; source_phase_time() = (uint8_t)colour_burst_time_; // assumption: burst was within the first 1/16 of the line } diff --git a/Outputs/CRT/Internals/CRTOpenGL.cpp b/Outputs/CRT/Internals/CRTOpenGL.cpp index 7282b771a..ab0597e10 100644 --- a/Outputs/CRT/Internals/CRTOpenGL.cpp +++ b/Outputs/CRT/Internals/CRTOpenGL.cpp @@ -69,9 +69,9 @@ OpenGLOutputBuilder::OpenGLOutputBuilder(size_t bytes_per_pixel) : // } // else { - composite_texture_.reset(new OpenGL::TextureTarget(IntermediateBufferWidth, IntermediateBufferHeight, composite_texture_unit)); - separated_texture_.reset(new OpenGL::TextureTarget(IntermediateBufferWidth, IntermediateBufferHeight, separated_texture_unit)); - filtered_texture_.reset(new OpenGL::TextureTarget(IntermediateBufferWidth, IntermediateBufferHeight, filtered_texture_unit)); + composite_texture_.reset(new OpenGL::TextureTarget(IntermediateBufferWidth, IntermediateBufferHeight, composite_texture_unit, GL_NEAREST)); + separated_texture_.reset(new OpenGL::TextureTarget(IntermediateBufferWidth, IntermediateBufferHeight, separated_texture_unit, GL_NEAREST)); + filtered_texture_.reset(new OpenGL::TextureTarget(IntermediateBufferWidth, IntermediateBufferHeight, filtered_texture_unit, GL_LINEAR)); } } @@ -117,7 +117,7 @@ void OpenGLOutputBuilder::draw_frame(unsigned int output_width, unsigned int out // make sure there's a target to draw to if(!framebuffer_ || framebuffer_->get_height() != output_height || framebuffer_->get_width() != output_width) { - std::unique_ptr new_framebuffer(new OpenGL::TextureTarget((GLsizei)output_width, (GLsizei)output_height, pixel_accumulation_texture_unit)); + std::unique_ptr new_framebuffer(new OpenGL::TextureTarget((GLsizei)output_width, (GLsizei)output_height, pixel_accumulation_texture_unit, GL_LINEAR)); if(framebuffer_) { new_framebuffer->bind_framebuffer(); @@ -346,6 +346,7 @@ void OpenGLOutputBuilder::prepare_output_shader() { output_shader_program_ = OpenGL::OutputShader::make_shader("", "texture(texID, srcCoordinatesVarying).rgb", false); output_shader_program_->set_source_texture_unit(work_texture_ ? work_texture_unit : filtered_texture_unit); +// output_shader_program_->set_source_texture_unit(composite_texture_unit); output_shader_program_->set_origin_is_double_height(!!work_texture_); } diff --git a/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp b/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp index 4325ae7b7..ddbe74792 100644 --- a/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp +++ b/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp @@ -75,7 +75,7 @@ std::unique_ptr IntermediateShader::make_shader(const char * // keep iInputPositionVarying in whole source pixels, scale mappedInputPosition to the ordinary normalised range "vec2 textureSize = vec2(textureSize(texID, 0));" "iInputPositionVarying = extendedInputPosition;" - "vec2 mappedInputPosition = (extendedInputPosition + vec2(0.0, 0.5)) / textureSize;" + "vec2 mappedInputPosition = (extendedInputPosition) / textureSize;" // + vec2(0.0, 0.5) // setup input positions spaced as per the supplied offsets; these are for filtering where required "inputPositionsVarying[0] = mappedInputPosition - (vec2(5.0, 0.0) / textureSize);" @@ -93,7 +93,8 @@ std::unique_ptr IntermediateShader::make_shader(const char * // setup phaseAndAmplitudeVarying.x as colour burst subcarrier phase, in radians; // setup phaseAndAmplitudeVarying.x as colour burst amplitude - "phaseAndAmplitudeVarying.x = (((extendedOutputPosition.x - phaseTimeAndAmplitude.y) / 4.0) + (phaseTimeAndAmplitude.x / 255.0)) * 2.0 * 3.141592654;" + "phaseAndAmplitudeVarying.x = (extendedOutputPosition.x - phaseTimeAndAmplitude.y*widthScalers[1]) / 4.0 + phaseTimeAndAmplitude.x / 255.0;" + "phaseAndAmplitudeVarying.x *= 2.0 * 3.141592654;" "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 @@ -187,7 +188,6 @@ std::unique_ptr IntermediateShader::make_chroma_luma_separat "in vec2 phaseAndAmplitudeVarying;" "in vec2 inputPositionsVarying[11];" - "uniform vec4 weights[3];" "out vec3 fragColour;" @@ -195,54 +195,16 @@ std::unique_ptr IntermediateShader::make_chroma_luma_separat "void main(void)" "{" - // grab 11 samples - "vec3 samples[] = vec3[](" - "vec3(" - "texture(texID, inputPositionsVarying[0]).r," - "texture(texID, inputPositionsVarying[2]).r," - "texture(texID, inputPositionsVarying[3]).r" - ")," - "vec3(" - "texture(texID, inputPositionsVarying[4]).r," - "texture(texID, inputPositionsVarying[5]).r," - "texture(texID, inputPositionsVarying[6]).r" - ")," - "vec3(" - "texture(texID, inputPositionsVarying[7]).r," - "texture(texID, inputPositionsVarying[8]).r," - "texture(texID, inputPositionsVarying[10]).r" - ")" + "vec4 samples = vec4(" + "texture(texID, inputPositionsVarying[3]).r," + "texture(texID, inputPositionsVarying[4]).r," + "texture(texID, inputPositionsVarying[5]).r," + "texture(texID, inputPositionsVarying[6]).r" ");" - - "vec3 fixedWeights[] = vec3[](" - "vec3(" - "-0.000918," - "0.027278," - "0.103969" - ")," - "vec3(" - "0.202962," - "0.250000," - "0.202962" - ")," - "vec3(" - "0.103969," - "0.027278," - "-0.000918" - ")" - ");" - - // apply the low-pass filter to separate luma - "float luminance = " - "dot(vec3(" - "dot(samples[0], fixedWeights[0])," - "dot(samples[1], fixedWeights[1])," - "dot(samples[2], fixedWeights[2])" - "), vec3(1.0));" - + "float luminance = dot(samples, vec4(0.25));" // define chroma to be whatever was here, minus luma - "float chrominance = 0.5 * (samples[1].y - luminance) / phaseAndAmplitudeVarying.y;" + "float chrominance = 0.5 * (samples.z - luminance) / phaseAndAmplitudeVarying.y;" "luminance /= (1.0 - phaseAndAmplitudeVarying.y);" // split choma colours here, as the most direct place, writing out @@ -268,48 +230,18 @@ std::unique_ptr IntermediateShader::make_chroma_filter_shade "void main(void)" "{" "vec3 samples[] = vec3[](" - "texture(texID, inputPositionsVarying[0]).rgb," - "texture(texID, inputPositionsVarying[2]).rgb," + "texture(texID, inputPositionsVarying[3]).rgb," "texture(texID, inputPositionsVarying[4]).rgb," "texture(texID, inputPositionsVarying[5]).rgb," - "texture(texID, inputPositionsVarying[6]).rgb," - "texture(texID, inputPositionsVarying[8]).rgb," - "texture(texID, inputPositionsVarying[10]).rgb" + "texture(texID, inputPositionsVarying[6]).rgb" ");" - "vec4 fixedWeights[2] = vec4[](" - "vec4(" - "0.001298," - "-0.038576," - "0.287031," - "0.500000" - ")," - "vec4(" - "0.287031," - "-0.038576," - "0.001298," - "0.0" - ")" - ");" + "vec4 chromaChannel1 = vec4(samples[0].g, samples[1].g, samples[2].g, samples[3].g);" + "vec4 chromaChannel2 = vec4(samples[0].b, samples[1].b, samples[2].b, samples[3].b);" - "vec4 chromaChannel1[] = vec4[](" - "vec4(samples[0].g, samples[1].g, samples[2].g, samples[3].g)," - "vec4(samples[4].g, samples[5].g, samples[6].g, 0.0)" - ");" - "vec4 chromaChannel2[] = vec4[](" - "vec4(samples[0].b, samples[1].b, samples[2].b, samples[3].b)," - "vec4(samples[4].b, samples[5].b, samples[6].b, 0.0)" - ");" - - "vec3 lumaChromaColour = vec3(samples[3].r," - "dot(vec2(" - "dot(chromaChannel1[0], fixedWeights[0])," - "dot(chromaChannel1[1], fixedWeights[1])" - "), vec2(1.0))," - "dot(vec2(" - "dot(chromaChannel2[0], fixedWeights[0])," - "dot(chromaChannel2[1], fixedWeights[1])" - "), vec2(1.0))" + "vec3 lumaChromaColour = vec3(samples[2].r," + "dot(chromaChannel1, vec4(0.25))," + "dot(chromaChannel2, vec4(0.25))" ");" "vec3 lumaChromaColourInRange = (lumaChromaColour - vec3(0.0, 0.5, 0.5)) * vec3(1.0, 2.0, 2.0);" diff --git a/Outputs/CRT/Internals/TextureTarget.cpp b/Outputs/CRT/Internals/TextureTarget.cpp index dccca91f7..54d2ede35 100644 --- a/Outputs/CRT/Internals/TextureTarget.cpp +++ b/Outputs/CRT/Internals/TextureTarget.cpp @@ -12,7 +12,7 @@ using namespace OpenGL; -TextureTarget::TextureTarget(GLsizei width, GLsizei height, GLenum texture_unit) : +TextureTarget::TextureTarget(GLsizei width, GLsizei height, GLenum texture_unit, GLint mag_filter) : _width(width), _height(height), _pixel_shader(nullptr), @@ -33,7 +33,7 @@ TextureTarget::TextureTarget(GLsizei width, GLsizei height, GLenum texture_unit) uint8_t *blank_buffer = (uint8_t *)calloc((size_t)(_expanded_width * _expanded_height), 4); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)_expanded_width, (GLsizei)_expanded_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, blank_buffer); free(blank_buffer); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _texture, 0); diff --git a/Outputs/CRT/Internals/TextureTarget.hpp b/Outputs/CRT/Internals/TextureTarget.hpp index 7e4b9dfef..aab1cc203 100644 --- a/Outputs/CRT/Internals/TextureTarget.hpp +++ b/Outputs/CRT/Internals/TextureTarget.hpp @@ -30,7 +30,7 @@ class TextureTarget { @param height The height of target to create. @param texture_unit A texture unit on which to bind the texture. */ - TextureTarget(GLsizei width, GLsizei height, GLenum texture_unit); + TextureTarget(GLsizei width, GLsizei height, GLenum texture_unit, GLint mag_filter); ~TextureTarget(); /*! From d0a93409e603acb5fcf2cead7e47aafa391d948b Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 11 Jan 2017 08:18:00 -0500 Subject: [PATCH 19/26] Made an attempt to simplify in-shader phase calculation, now that output position is a direct multiple of phase. --- Outputs/CRT/CRT.cpp | 12 ++++++------ Outputs/CRT/CRT.hpp | 1 - Outputs/CRT/Internals/Shaders/IntermediateShader.cpp | 3 +-- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/Outputs/CRT/CRT.cpp b/Outputs/CRT/CRT.cpp index db55f4f63..d613197ce 100644 --- a/Outputs/CRT/CRT.cpp +++ b/Outputs/CRT/CRT.cpp @@ -112,7 +112,6 @@ Flywheel::SyncEvent CRT::get_next_horizontal_sync_event(bool hsync_is_requested, #define source_output_position_x2() (*(uint16_t *)&next_run[SourceVertexOffsetOfEnds + 2]) #define source_phase() next_run[SourceVertexOffsetOfPhaseTimeAndAmplitude + 0] #define source_amplitude() next_run[SourceVertexOffsetOfPhaseTimeAndAmplitude + 2] -#define source_phase_time() next_run[SourceVertexOffsetOfPhaseTimeAndAmplitude + 1] void CRT::advance_cycles(unsigned int number_of_cycles, bool hsync_requested, bool vsync_requested, const bool vsync_charging, const Scan::Type type) { @@ -147,9 +146,8 @@ void CRT::advance_cycles(unsigned int number_of_cycles, bool hsync_requested, bo { // output_y and texture locations will be written later; we won't necessarily know what it is outside of the locked region source_output_position_x1() = (uint16_t)horizontal_flywheel_->get_current_output_position(); - source_phase() = 31 + colour_burst_phase_ & ~63; // phase is rounded to the nearest 1/4 of a cycle + source_phase() = colour_burst_phase_; source_amplitude() = colour_burst_amplitude_; - source_phase_time() = (uint8_t)colour_burst_time_; // assumption: burst was within the first 1/16 of the line } // decrement the number of cycles left to run for and increment the @@ -288,9 +286,11 @@ void CRT::output_scan(const Scan *const scan) { if(horizontal_flywheel_->get_current_time() < (horizontal_flywheel_->get_standard_period() * 12) >> 6) { - colour_burst_time_ = (uint16_t)horizontal_flywheel_->get_current_time(); - colour_burst_phase_ = scan->phase; + unsigned int position_phase = (horizontal_flywheel_->get_current_time() * colour_cycle_numerator_ * 256) / phase_denominator_; + colour_burst_phase_ = (position_phase + scan->phase) & 255; colour_burst_amplitude_ = scan->amplitude; + + colour_burst_phase_ &= ~63; } } @@ -346,7 +346,7 @@ void CRT::output_default_colour_burst(unsigned int number_of_cycles) Scan scan { .type = Scan::Type::ColourBurst, .number_of_cycles = number_of_cycles, - .phase = (uint8_t)((phase_numerator_ * 255) / phase_denominator_ + (is_alernate_line_ ? 128 : 0)), + .phase = (uint8_t)((phase_numerator_ * 256) / phase_denominator_ + (is_alernate_line_ ? 128 : 0)), .amplitude = 32 }; output_scan(&scan); diff --git a/Outputs/CRT/CRT.hpp b/Outputs/CRT/CRT.hpp index 0b07910f9..af06af273 100644 --- a/Outputs/CRT/CRT.hpp +++ b/Outputs/CRT/CRT.hpp @@ -60,7 +60,6 @@ class CRT { void output_scan(const Scan *scan); uint8_t colour_burst_phase_, colour_burst_amplitude_; - uint16_t colour_burst_time_; bool is_writing_composite_run_; unsigned int phase_denominator_, phase_numerator_, colour_cycle_numerator_; diff --git a/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp b/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp index ddbe74792..b4a93a1e0 100644 --- a/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp +++ b/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp @@ -93,8 +93,7 @@ std::unique_ptr IntermediateShader::make_shader(const char * // setup phaseAndAmplitudeVarying.x as colour burst subcarrier phase, in radians; // setup phaseAndAmplitudeVarying.x as colour burst amplitude - "phaseAndAmplitudeVarying.x = (extendedOutputPosition.x - phaseTimeAndAmplitude.y*widthScalers[1]) / 4.0 + phaseTimeAndAmplitude.x / 255.0;" - "phaseAndAmplitudeVarying.x *= 2.0 * 3.141592654;" + "phaseAndAmplitudeVarying.x = (extendedOutputPosition.x + (phaseTimeAndAmplitude.x / 64.0)) * 0.5 * 3.141592654;" "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 From b4159295f61d1789d6a1317afe54128a531020fd Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 11 Jan 2017 21:18:41 -0500 Subject: [PATCH 20/26] Switched to using quads for intermediate draws. The specific concern is the flexibility offered in the GL spec as to line drawing algorithms. And even if a driver implements exactly to spec then it should omit the final pixel. --- Outputs/CRT/Internals/CRTOpenGL.cpp | 2 +- Outputs/CRT/Internals/Shaders/IntermediateShader.cpp | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Outputs/CRT/Internals/CRTOpenGL.cpp b/Outputs/CRT/Internals/CRTOpenGL.cpp index ab0597e10..9938d58f1 100644 --- a/Outputs/CRT/Internals/CRTOpenGL.cpp +++ b/Outputs/CRT/Internals/CRTOpenGL.cpp @@ -206,7 +206,7 @@ void OpenGLOutputBuilder::draw_frame(unsigned int output_width, unsigned int out } // draw - glDrawArraysInstanced(GL_LINES, 0, 2, (GLsizei)array_submission.input_size / SourceVertexSize); + glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, (GLsizei)array_submission.input_size / SourceVertexSize); active_pipeline++; #ifdef GL_NV_texture_barrier diff --git a/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp b/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp index b4a93a1e0..870eef24f 100644 --- a/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp +++ b/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp @@ -58,6 +58,7 @@ std::unique_ptr IntermediateShader::make_shader(const char * "{" // odd vertices are on the left, even on the right "float extent = float(gl_VertexID & 1);" + "float longitudinal = float((gl_VertexID & 2) >> 1);" // inputPosition.x is either inputStart.x or ends.x, depending on whether it is on the left or the right; // outputPosition.x is either outputStart.x or ends.y; @@ -65,6 +66,9 @@ std::unique_ptr IntermediateShader::make_shader(const char * "vec2 inputPosition = vec2(mix(inputStart.x, ends.x, extent)*widthScalers[0], inputStart.y + inputVerticalOffset);" "vec2 outputPosition = vec2(mix(outputStart.x, ends.y, extent)*widthScalers[1], outputStart.y + outputVerticalOffset);" + "inputPosition.y += longitudinal;" + "outputPosition.y += longitudinal;" + // extension is the amount to extend both the input and output by to add a full colour cycle at each end "vec2 extensionVector = vec2(extension, 0.0) * 2.0 * (extent - 0.5);" @@ -75,7 +79,7 @@ std::unique_ptr IntermediateShader::make_shader(const char * // keep iInputPositionVarying in whole source pixels, scale mappedInputPosition to the ordinary normalised range "vec2 textureSize = vec2(textureSize(texID, 0));" "iInputPositionVarying = extendedInputPosition;" - "vec2 mappedInputPosition = (extendedInputPosition) / textureSize;" // + vec2(0.0, 0.5) + "vec2 mappedInputPosition = extendedInputPosition / textureSize;" // + vec2(0.0, 0.5) // setup input positions spaced as per the supplied offsets; these are for filtering where required "inputPositionsVarying[0] = mappedInputPosition - (vec2(5.0, 0.0) / textureSize);" From be1cb2a551b13b3a9273d2ae73596dc0b36ca97c Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 11 Jan 2017 21:31:24 -0500 Subject: [PATCH 21/26] Fixed NTSC phase. --- Machines/Atari2600/Atari2600.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Machines/Atari2600/Atari2600.cpp b/Machines/Atari2600/Atari2600.cpp index 47df984ea..9037a6c43 100644 --- a/Machines/Atari2600/Atari2600.cpp +++ b/Machines/Atari2600/Atari2600.cpp @@ -71,7 +71,7 @@ void Machine::setup_output(float aspect_ratio) "uint y = c & 14u;" "uint iPhase = (c >> 4);" - "float phaseOffset = 6.283185308 * float(iPhase - 1u) / 13.0;" + "float phaseOffset = 6.283185308 * float(iPhase) / 13.0 + 5.074880441076923;" "return mix(float(y) / 14.0, step(1, iPhase) * cos(phase + phaseOffset), amplitude);" "}"); speaker_->set_input_rate((float)(get_clock_rate() / 38.0)); From ced644b1038981cc8dec416ea2290939121100a2 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 11 Jan 2017 22:03:01 -0500 Subject: [PATCH 22/26] It seems likely that an AY divides its clock by 8, not 16. I had conflated wave frequency and counter clock. --- Components/AY38910/AY38910.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Components/AY38910/AY38910.cpp b/Components/AY38910/AY38910.cpp index 93534d872..2ac9d3177 100644 --- a/Components/AY38910/AY38910.cpp +++ b/Components/AY38910/AY38910.cpp @@ -84,7 +84,7 @@ void AY38910::set_clock_rate(double clock_rate) void AY38910::get_samples(unsigned int number_of_samples, int16_t *target) { int c = 0; - while((master_divider_&15) && c < number_of_samples) + while((master_divider_&7) && c < number_of_samples) { target[c] = output_volume_; master_divider_++; @@ -131,7 +131,7 @@ void AY38910::get_samples(unsigned int number_of_samples, int16_t *target) evaluate_output_volume(); - for(int ic = 0; ic < 16 && c < number_of_samples; ic++) + for(int ic = 0; ic < 8 && c < number_of_samples; ic++) { target[c] = output_volume_; c++; @@ -139,7 +139,7 @@ void AY38910::get_samples(unsigned int number_of_samples, int16_t *target) } } - master_divider_ &= 15; + master_divider_ &= 7; } void AY38910::evaluate_output_volume() From 5761c8267bf2346993d89f68a6630b8087439687 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 24 Jan 2017 20:48:54 -0500 Subject: [PATCH 23/26] [Re-]Eliminated connection between colour subcarrier frequency and monitor output mode. --- Outputs/CRT/Internals/CRTOpenGL.cpp | 28 ++++++++++++++++++++++++---- Outputs/CRT/Internals/CRTOpenGL.hpp | 2 ++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/Outputs/CRT/Internals/CRTOpenGL.cpp b/Outputs/CRT/Internals/CRTOpenGL.cpp index 9938d58f1..82aba1980 100644 --- a/Outputs/CRT/Internals/CRTOpenGL.cpp +++ b/Outputs/CRT/Internals/CRTOpenGL.cpp @@ -371,6 +371,7 @@ void OpenGLOutputBuilder::set_output_device(OutputDevice output_device) composite_src_output_y_ = 0; last_output_width_ = 0; last_output_height_ = 0; + set_output_shader_width(); } } @@ -418,10 +419,29 @@ void OpenGLOutputBuilder::set_colour_space_uniforms() if(composite_chrominance_filter_shader_program_) composite_chrominance_filter_shader_program_->set_colour_conversion_matrices(fromRGB, toRGB); } +float OpenGLOutputBuilder::get_composite_output_width() const +{ + return ((float)colour_cycle_numerator_ * 4.0f) / (float)(colour_cycle_denominator_ * IntermediateBufferWidth); +} + +void OpenGLOutputBuilder::set_output_shader_width() +{ + if(output_shader_program_) + { + float width = 1.0f; + switch(output_device_) + { + case Television: width = get_composite_output_width(); break; + case Monitor: width = 1.0f; break; + } + output_shader_program_->set_input_width_scaler(width); + } +} + void OpenGLOutputBuilder::set_timing_uniforms() { const float colour_subcarrier_frequency = (float)colour_cycle_numerator_ / (float)colour_cycle_denominator_; - const float output_width = ((float)colour_cycle_numerator_ * 4.0f) / (float)(colour_cycle_denominator_ * IntermediateBufferWidth); + const float output_width = get_composite_output_width(); const float sample_cycles_per_line = cycles_per_line_ / output_width; if(composite_separation_filter_program_) @@ -437,12 +457,12 @@ void OpenGLOutputBuilder::set_timing_uniforms() } if(rgb_filter_shader_program_) { - rgb_filter_shader_program_->set_width_scalers(output_width, output_width); + rgb_filter_shader_program_->set_width_scalers(1.0f, 1.0f); rgb_filter_shader_program_->set_filter_coefficients(sample_cycles_per_line, (float)input_frequency_ * 0.5f); } if(output_shader_program_) { - output_shader_program_->set_input_width_scaler(output_width); + set_output_shader_width(); output_shader_program_->set_timing(height_of_display_, cycles_per_line_, horizontal_scan_period_, vertical_scan_period_, vertical_period_divider_); } if(composite_input_shader_program_) @@ -452,6 +472,6 @@ void OpenGLOutputBuilder::set_timing_uniforms() } if(rgb_input_shader_program_) { - rgb_input_shader_program_->set_width_scalers(1.0f, output_width); + rgb_input_shader_program_->set_width_scalers(1.0f, 1.0f); } } diff --git a/Outputs/CRT/Internals/CRTOpenGL.hpp b/Outputs/CRT/Internals/CRTOpenGL.hpp index 551a20193..6341b43bb 100644 --- a/Outputs/CRT/Internals/CRTOpenGL.hpp +++ b/Outputs/CRT/Internals/CRTOpenGL.hpp @@ -94,6 +94,8 @@ class OpenGLOutputBuilder { void reset_all_OpenGL_state(); GLsync fence_; + float get_composite_output_width() const; + void set_output_shader_width(); public: // These two are protected by output_mutex_. From 4d6e78e64164064f699b4578675cb57eb34ec24a Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 24 Jan 2017 22:16:15 -0500 Subject: [PATCH 24/26] Reinstated temporary Oric-related fix. --- Outputs/CRT/CRT.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Outputs/CRT/CRT.cpp b/Outputs/CRT/CRT.cpp index d613197ce..f1d0c3f88 100644 --- a/Outputs/CRT/CRT.cpp +++ b/Outputs/CRT/CRT.cpp @@ -290,7 +290,7 @@ void CRT::output_scan(const Scan *const scan) colour_burst_phase_ = (position_phase + scan->phase) & 255; colour_burst_amplitude_ = scan->amplitude; - colour_burst_phase_ &= ~63; + colour_burst_phase_ = (colour_burst_phase_ & ~63) + 32; } } From c2d7e36c8f00f24716f5320315532a21b3ee4841 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 25 Jan 2017 21:25:03 -0500 Subject: [PATCH 25/26] Ensured logic for whether composite output is in use is consistent. --- Outputs/CRT/Internals/CRTOpenGL.cpp | 14 +++++++------- Outputs/CRT/Internals/CRTOpenGL.hpp | 1 + 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Outputs/CRT/Internals/CRTOpenGL.cpp b/Outputs/CRT/Internals/CRTOpenGL.cpp index 82aba1980..2b471fa3d 100644 --- a/Outputs/CRT/Internals/CRTOpenGL.cpp +++ b/Outputs/CRT/Internals/CRTOpenGL.cpp @@ -83,6 +83,11 @@ OpenGLOutputBuilder::~OpenGLOutputBuilder() free(rgb_shader_); } +bool OpenGLOutputBuilder::get_is_television_output() +{ + return output_device_ == Television || !rgb_input_shader_program_; +} + void OpenGLOutputBuilder::draw_frame(unsigned int output_width, unsigned int output_height, bool only_if_dirty) { // lock down any other draw_frames @@ -171,7 +176,7 @@ void OpenGLOutputBuilder::draw_frame(unsigned int output_width, unsigned int out {nullptr} }; - RenderStage *active_pipeline = (output_device_ == Television || !rgb_input_shader_program_) ? composite_render_stages : rgb_render_stages; + RenderStage *active_pipeline = get_is_television_output() ? composite_render_stages : rgb_render_stages; if(array_submission.input_size || array_submission.output_size) { @@ -428,12 +433,7 @@ void OpenGLOutputBuilder::set_output_shader_width() { if(output_shader_program_) { - float width = 1.0f; - switch(output_device_) - { - case Television: width = get_composite_output_width(); break; - case Monitor: width = 1.0f; break; - } + const float width = get_is_television_output() ? get_composite_output_width() : 1.0f; output_shader_program_->set_input_width_scaler(width); } } diff --git a/Outputs/CRT/Internals/CRTOpenGL.hpp b/Outputs/CRT/Internals/CRTOpenGL.hpp index 6341b43bb..b14d49e28 100644 --- a/Outputs/CRT/Internals/CRTOpenGL.hpp +++ b/Outputs/CRT/Internals/CRTOpenGL.hpp @@ -96,6 +96,7 @@ class OpenGLOutputBuilder { GLsync fence_; float get_composite_output_width() const; void set_output_shader_width(); + bool get_is_television_output(); public: // These two are protected by output_mutex_. From 6d087ca0547dbedb8334361cd23b5c99ccc00216 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 25 Jan 2017 21:29:19 -0500 Subject: [PATCH 26/26] Restored 2600 audio. --- Machines/Atari2600/Atari2600.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Machines/Atari2600/Atari2600.cpp b/Machines/Atari2600/Atari2600.cpp index 9037a6c43..ea96ea83c 100644 --- a/Machines/Atari2600/Atari2600.cpp +++ b/Machines/Atari2600/Atari2600.cpp @@ -777,5 +777,6 @@ void Machine::update_audio() void Machine::synchronise() { update_audio(); + speaker_->flush(); }