1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-06 01:28:57 +00:00

Introduced a separate stage for luminance filtering.

This commit is contained in:
Thomas Harte 2016-05-03 07:46:40 -04:00
parent 1bb92550f8
commit 31f1e6d5c0
4 changed files with 106 additions and 54 deletions

View File

@ -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<OpenGL::TextureTarget>(new OpenGL::TextureTarget(IntermediateBufferWidth, IntermediateBufferHeight, composite_texture_unit));
separatedTexture = std::unique_ptr<OpenGL::TextureTarget>(new OpenGL::TextureTarget(IntermediateBufferWidth, IntermediateBufferHeight, separated_texture_unit));
filteredYTexture = std::unique_ptr<OpenGL::TextureTarget>(new OpenGL::TextureTarget(IntermediateBufferWidth, IntermediateBufferHeight, filtered_y_texture_unit));
filteredTexture = std::unique_ptr<OpenGL::TextureTarget>(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);

View File

@ -63,9 +63,16 @@ class OpenGLOutputBuilder {
uint16_t _composite_src_output_y, _cleared_composite_output_y;
std::unique_ptr<OpenGL::OutputShader> output_shader_program;
std::unique_ptr<OpenGL::IntermediateShader> composite_input_shader_program, composite_y_filter_shader_program, composite_chrominance_filter_shader_program;
std::unique_ptr<OpenGL::IntermediateShader> composite_input_shader_program, composite_separation_filter_program, composite_y_filter_shader_program, composite_chrominance_filter_shader_program;
std::unique_ptr<OpenGL::IntermediateShader> rgb_input_shader_program, rgb_filter_shader_program;
std::unique_ptr<OpenGL::TextureTarget> compositeTexture; // receives raw composite levels
std::unique_ptr<OpenGL::TextureTarget> separatedTexture; // receives unfiltered Y in the R channel plus unfiltered but demodulated chrominance in G and B
std::unique_ptr<OpenGL::TextureTarget> filteredYTexture; // receives filtered Y in the R channel plus unfiltered chrominance in G and B
std::unique_ptr<OpenGL::TextureTarget> filteredTexture; // receives filtered YIQ or YUV
std::unique_ptr<OpenGL::TextureTarget> 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<OpenGL::TextureTarget> compositeTexture; // receives raw composite levels
std::unique_ptr<OpenGL::TextureTarget> filteredYTexture; // receives filtered Y in the R channel plus unfiltered I/U and Q/V in G and B
std::unique_ptr<OpenGL::TextureTarget> filteredTexture; // receives filtered YIQ or YUV
std::unique_ptr<OpenGL::TextureTarget> 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();

View File

@ -210,7 +210,7 @@ std::unique_ptr<IntermediateShader> 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> 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> IntermediateShader::make_chroma_filter_shade
"}", false, false);
}
std::unique_ptr<IntermediateShader> 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> 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)

View File

@ -44,6 +44,11 @@ public:
*/
static std::unique_ptr<IntermediateShader> 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<IntermediateShader> make_luma_filter_shader();
/*!
Constructs and returns an intermediate shader that will filter R, G and B.
*/