diff --git a/Outputs/CRT/Internals/CRTOpenGL.cpp b/Outputs/CRT/Internals/CRTOpenGL.cpp index 79f8b3916..33fa3e598 100644 --- a/Outputs/CRT/Internals/CRTOpenGL.cpp +++ b/Outputs/CRT/Internals/CRTOpenGL.cpp @@ -74,11 +74,12 @@ static int getCircularRanges(GLsizei start, GLsizei end, GLsizei buffer_length, using namespace Outputs::CRT; namespace { - static const GLenum composite_texture_unit = GL_TEXTURE0; - static const GLenum filtered_y_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 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; } OpenGLOutputBuilder::OpenGLOutputBuilder(unsigned int buffer_depth) : @@ -105,6 +106,7 @@ OpenGLOutputBuilder::OpenGLOutputBuilder(unsigned int buffer_depth) : // Create intermediate textures and bind to slots 0, 1 and 2 compositeTexture = std::unique_ptr(new OpenGL::TextureTarget(IntermediateBufferWidth, IntermediateBufferHeight, composite_texture_unit)); + separatedTexture = std::unique_ptr(new OpenGL::TextureTarget(IntermediateBufferWidth, IntermediateBufferHeight, separated_texture_unit)); filteredYTexture = std::unique_ptr(new OpenGL::TextureTarget(IntermediateBufferWidth, IntermediateBufferHeight, filtered_y_texture_unit)); filteredTexture = std::unique_ptr(new OpenGL::TextureTarget(IntermediateBufferWidth, IntermediateBufferHeight, filtered_texture_unit)); @@ -250,6 +252,7 @@ void OpenGLOutputBuilder::draw_frame(unsigned int output_width, unsigned int out RenderStage composite_render_stages[] = { {compositeTexture.get(), composite_input_shader_program.get(), {0.0, 0.0, 0.0}}, + {separatedTexture.get(), composite_separation_filter_program.get(), {0.0, 0.5, 0.5}}, {filteredYTexture.get(), composite_y_filter_shader_program.get(), {0.0, 0.5, 0.5}}, {filteredTexture.get(), composite_chrominance_filter_shader_program.get(), {0.0, 0.0, 0.0}}, {nullptr} @@ -377,13 +380,6 @@ void OpenGLOutputBuilder::draw_frame(unsigned int output_width, unsigned int out _output_mutex->unlock(); } -void OpenGLOutputBuilder::perform_output_stage(unsigned int output_width, unsigned int output_height, OpenGL::OutputShader *const shader) -{ - if(shader) - { - } -} - void OpenGLOutputBuilder::set_openGL_context_will_change(bool should_delete_resources) { } @@ -406,8 +402,12 @@ void OpenGLOutputBuilder::prepare_composite_input_shaders() composite_input_shader_program->set_source_texture_unit(source_data_texture_unit); composite_input_shader_program->set_output_size(IntermediateBufferWidth, IntermediateBufferHeight); - composite_y_filter_shader_program = OpenGL::IntermediateShader::make_chroma_luma_separation_shader(); - composite_y_filter_shader_program->set_source_texture_unit(composite_texture_unit); + 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_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(); @@ -533,7 +533,7 @@ void OpenGLOutputBuilder::set_colour_space_uniforms() break; } - if(composite_input_shader_program) composite_input_shader_program->set_colour_conversion_matrices(fromRGB, toRGB); + if(composite_input_shader_program) composite_input_shader_program->set_colour_conversion_matrices(fromRGB, toRGB); if(composite_chrominance_filter_shader_program) composite_chrominance_filter_shader_program->set_colour_conversion_matrices(fromRGB, toRGB); _output_mutex->unlock(); } @@ -544,6 +544,7 @@ 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() }; @@ -558,7 +559,8 @@ void OpenGLOutputBuilder::set_timing_uniforms() 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_y_filter_shader_program) composite_y_filter_shader_program->set_separation_frequency(_cycles_per_line, colour_subcarrier_frequency); + 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.75f); 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); diff --git a/Outputs/CRT/Internals/CRTOpenGL.hpp b/Outputs/CRT/Internals/CRTOpenGL.hpp index 7014d9c07..5015d2486 100644 --- a/Outputs/CRT/Internals/CRTOpenGL.hpp +++ b/Outputs/CRT/Internals/CRTOpenGL.hpp @@ -63,9 +63,16 @@ class OpenGLOutputBuilder { uint16_t _composite_src_output_y, _cleared_composite_output_y; std::unique_ptr output_shader_program; - std::unique_ptr composite_input_shader_program, composite_y_filter_shader_program, composite_chrominance_filter_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 rgb_input_shader_program, rgb_filter_shader_program; + std::unique_ptr compositeTexture; // receives raw composite levels + std::unique_ptr separatedTexture; // receives unfiltered Y in the R channel plus unfiltered but demodulated chrominance in G and B + std::unique_ptr filteredYTexture; // receives filtered Y in the R channel plus unfiltered chrominance in G and B + std::unique_ptr filteredTexture; // receives filtered YIQ or YUV + + std::unique_ptr framebuffer; // the current pixel output + GLuint output_array_buffer, output_vertex_array; GLuint source_array_buffer, source_vertex_array; @@ -75,13 +82,6 @@ class OpenGLOutputBuilder { GLuint defaultFramebuffer; - std::unique_ptr compositeTexture; // receives raw composite levels - std::unique_ptr filteredYTexture; // receives filtered Y in the R channel plus unfiltered I/U and Q/V in G and B - std::unique_ptr filteredTexture; // receives filtered YIQ or YUV - - std::unique_ptr framebuffer; // the current pixel output - - void perform_output_stage(unsigned int output_width, unsigned int output_height, OpenGL::OutputShader *const shader); void set_timing_uniforms(); void set_colour_space_uniforms(); diff --git a/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp b/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp index faaa8a37c..a72520df7 100644 --- a/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp +++ b/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp @@ -210,7 +210,7 @@ std::unique_ptr IntermediateShader::make_chroma_luma_separat "dot(samples[0], weights[0])," "dot(samples[1], weights[1])," "dot(samples[2], weights[2])" - "), vec3(1.0)) / (1.0 - phaseAndAmplitudeVarying.y);" + "), vec3(1.0));" "float chrominance = 0.5 * (samples[1].y - luminance) / phaseAndAmplitudeVarying.y;" "vec2 quadrature = vec2(cos(phaseAndAmplitudeVarying.x), -sin(phaseAndAmplitudeVarying.x));" @@ -234,43 +234,42 @@ std::unique_ptr IntermediateShader::make_chroma_filter_shade "void main(void)" "{" - "vec3 centreSample = texture(texID, inputPositionsVarying[5]).rgb;" - "vec2 samples[] = vec2[](" - "texture(texID, inputPositionsVarying[0]).gb - vec2(0.5)," - "texture(texID, inputPositionsVarying[1]).gb - vec2(0.5)," - "texture(texID, inputPositionsVarying[2]).gb - vec2(0.5)," - "texture(texID, inputPositionsVarying[3]).gb - vec2(0.5)," - "texture(texID, inputPositionsVarying[4]).gb - vec2(0.5)," - "centreSample.gb - vec2(0.5)," - "texture(texID, inputPositionsVarying[6]).gb - vec2(0.5)," - "texture(texID, inputPositionsVarying[7]).gb - vec2(0.5)," - "texture(texID, inputPositionsVarying[8]).gb - vec2(0.5)," - "texture(texID, inputPositionsVarying[9]).gb - vec2(0.5)," - "texture(texID, inputPositionsVarying[10]).gb - vec2(0.5)" + "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 channel1[] = 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 channel2[] = vec4[](" + "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 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)" + ");" - "vec3 lumaChromaColour = vec3(centreSample.r," + "vec3 lumaChromaColour = vec3(samples[5].r," "dot(vec3(" - "dot(channel1[0], weights[0])," - "dot(channel1[1], weights[1])," - "dot(channel1[2], weights[2])" - "), vec3(1.0)) + 0.5," + "dot(chromaChannel1[0], weights[0])," + "dot(chromaChannel1[1], weights[1])," + "dot(chromaChannel1[2], weights[2])" + "), vec3(1.0))," "dot(vec3(" - "dot(channel2[0], weights[0])," - "dot(channel2[1], weights[1])," - "dot(channel2[2], weights[2])" - "), vec3(1.0)) + 0.5" + "dot(chromaChannel2[0], weights[0])," + "dot(chromaChannel2[1], weights[1])," + "dot(chromaChannel2[2], weights[2])" + "), vec3(1.0))" ");" "vec3 lumaChromaColourInRange = (lumaChromaColour - vec3(0.0, 0.5, 0.5)) * vec3(1.0, 2.0, 2.0);" @@ -278,6 +277,52 @@ 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" + ");" + "}", false, false); +} + std::unique_ptr IntermediateShader::make_rgb_filter_shader() { return make_shader( @@ -414,7 +459,7 @@ void IntermediateShader::set_filter_coefficients(float sampling_rate, float cuto void IntermediateShader::set_separation_frequency(float sampling_rate, float colour_burst_frequency) { // TODO: apply separately-formed filters for luminance and chrominance - set_filter_coefficients(sampling_rate, colour_burst_frequency - 50.0f); + 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) diff --git a/Outputs/CRT/Internals/Shaders/IntermediateShader.hpp b/Outputs/CRT/Internals/Shaders/IntermediateShader.hpp index db4f76199..821a5a717 100644 --- a/Outputs/CRT/Internals/Shaders/IntermediateShader.hpp +++ b/Outputs/CRT/Internals/Shaders/IntermediateShader.hpp @@ -44,6 +44,11 @@ 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. */