From 46d756d2980df77c1b37e403ebcce204c466e844 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 5 Jan 2019 18:11:39 -0500 Subject: [PATCH] Starts towards a flattening of the intermediate video processing. Immediate issue: using x position to index into a bitmap sampled at the input data rate doesn't allow for the disconnection between input rate and output speed provided by the flywheels. --- Outputs/OpenGL/Primitives/Shader.cpp | 21 +++++----- Outputs/OpenGL/ScanTarget.cpp | 26 +++++++++--- Outputs/OpenGL/ScanTarget.hpp | 2 +- Outputs/OpenGL/ScanTargetGLSLFragments.cpp | 47 +++++++++++++++++----- 4 files changed, 71 insertions(+), 25 deletions(-) diff --git a/Outputs/OpenGL/Primitives/Shader.cpp b/Outputs/OpenGL/Primitives/Shader.cpp index 6b08fcc11..7290cfe39 100644 --- a/Outputs/OpenGL/Primitives/Shader.cpp +++ b/Outputs/OpenGL/Primitives/Shader.cpp @@ -47,8 +47,8 @@ GLuint Shader::compile_shader(const std::string &source, GLenum type) { Shader::Shader(const std::string &vertex_shader, const std::string &fragment_shader, const std::vector &attribute_bindings) { shader_program_ = glCreateProgram(); - GLuint vertex = compile_shader(vertex_shader, GL_VERTEX_SHADER); - GLuint fragment = compile_shader(fragment_shader, GL_FRAGMENT_SHADER); + const GLuint vertex = compile_shader(vertex_shader, GL_VERTEX_SHADER); + const GLuint fragment = compile_shader(fragment_shader, GL_FRAGMENT_SHADER); glAttachShader(shader_program_, vertex); glAttachShader(shader_program_, fragment); @@ -60,17 +60,18 @@ Shader::Shader(const std::string &vertex_shader, const std::string &fragment_sha glLinkProgram(shader_program_); #ifdef DEBUG + GLint logLength; + glGetProgramiv(shader_program_, GL_INFO_LOG_LENGTH, &logLength); + if(logLength > 0) { + GLchar *log = new GLchar[static_cast(logLength)]; + glGetProgramInfoLog(shader_program_, logLength, &logLength, log); + printf("Link log:\n%s\n", log); + delete[] log; + } + GLint didLink = 0; glGetProgramiv(shader_program_, GL_LINK_STATUS, &didLink); if(didLink == GL_FALSE) { - GLint logLength; - glGetProgramiv(shader_program_, GL_INFO_LOG_LENGTH, &logLength); - if(logLength > 0) { - GLchar *log = new GLchar[static_cast(logLength)]; - glGetProgramInfoLog(shader_program_, logLength, &logLength, log); - printf("Link log:\n%s\n", log); - delete[] log; - } throw ProgramLinkageError; } #endif diff --git a/Outputs/OpenGL/ScanTarget.cpp b/Outputs/OpenGL/ScanTarget.cpp index a7805df1a..787b471c5 100644 --- a/Outputs/OpenGL/ScanTarget.cpp +++ b/Outputs/OpenGL/ScanTarget.cpp @@ -14,10 +14,10 @@ using namespace Outputs::Display::OpenGL; namespace { /// The texture unit from which to source input data. -constexpr GLenum SourceDataTextureUnit = GL_TEXTURE0; +constexpr GLenum SourceDataTextureUnit = GL_TEXTURE1; /// The texture unit which contains raw line-by-line composite, S-Video or RGB data. -constexpr GLenum UnprocessedLineBufferTextureUnit = GL_TEXTURE1; +constexpr GLenum UnprocessedLineBufferTextureUnit = GL_TEXTURE3; /// The texture unit that contains the current display. constexpr GLenum AccumulationTextureUnit = GL_TEXTURE2; @@ -288,7 +288,7 @@ void ScanTarget::setup_pipeline() { // lose any detail when combining the input. processing_width_ = modals_.cycles_per_line / modals_.clocks_per_pixel_greatest_common_divisor; - // Establish an output shader. TODO: add gamma correction here. + // Establish an output shader. TODO: add proper decoding and gamma correction here. output_shader_.reset(new Shader( glsl_globals(ShaderType::Line) + glsl_default_vertex_shader(ShaderType::Line), "#version 150\n" @@ -312,8 +312,24 @@ void ScanTarget::setup_pipeline() { output_shader_->set_uniform("size", modals_.visible_area.size.width, modals_.visible_area.size.height); output_shader_->set_uniform("textureName", GLint(UnprocessedLineBufferTextureUnit - GL_TEXTURE0)); +// switch(modals_.composite_colour_space) { +// case ColourSpace::YIQ: { +// const GLfloat rgbToYIQ[] = {0.299f, 0.596f, 0.211f, 0.587f, -0.274f, -0.523f, 0.114f, -0.322f, 0.312f}; +// const GLfloat yiqToRGB[] = {1.0f, 1.0f, 1.0f, 0.956f, -0.272f, -1.106f, 0.621f, -0.647f, 1.703f}; +// shader->set_uniform_matrix("lumaChromaToRGB", 3, false, yiqToRGB); +// shader->set_uniform_matrix("rgbToLumaChroma", 3, false, rgbToYIQ); +// } break; +// +// case ColourSpace::YUV: { +// const GLfloat rgbToYUV[] = {0.299f, -0.14713f, 0.615f, 0.587f, -0.28886f, -0.51499f, 0.114f, 0.436f, -0.10001f}; +// const GLfloat yuvToRGB[] = {1.0f, 1.0f, 1.0f, 0.0f, -0.39465f, 2.03211f, 1.13983f, -0.58060f, 0.0f}; +// shader->set_uniform_matrix("lumaChromaToRGB", 3, false, yuvToRGB); +// shader->set_uniform_matrix("rgbToLumaChroma", 3, false, rgbToYUV); +// } break; +// } + // Establish an input shader. - input_shader_ = composition_shader(); + input_shader_ = composition_shader(modals_.input_data_type); glBindVertexArray(scan_vertex_array_); glBindBuffer(GL_ARRAY_BUFFER, scan_buffer_name_); enable_vertex_attributes(ShaderType::InputScan, *input_shader_); @@ -492,7 +508,7 @@ void ScanTarget::draw(bool synchronous, int output_width, int output_height) { // Enable blending and stenciling, and ensure spans increment the stencil buffer. glEnable(GL_BLEND); glEnable(GL_STENCIL_TEST); - glStencilFunc(GL_EQUAL, 0, GLuint(-1)); + glStencilFunc(GL_EQUAL, 0, GLuint(~0)); glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); // Prepare to output lines. diff --git a/Outputs/OpenGL/ScanTarget.hpp b/Outputs/OpenGL/ScanTarget.hpp index 53fe8a5b8..669239167 100644 --- a/Outputs/OpenGL/ScanTarget.hpp +++ b/Outputs/OpenGL/ScanTarget.hpp @@ -179,7 +179,7 @@ class ScanTarget: public Outputs::Display::ScanTarget { std::unique_ptr input_shader_; std::unique_ptr output_shader_; - static std::unique_ptr composition_shader(); + static std::unique_ptr composition_shader(InputDataType input_data_type); static std::unique_ptr conversion_shader(InputDataType input_data_type, DisplayType display_type, int colour_cycle_numerator, int colour_cycle_denominator, int processing_width); }; diff --git a/Outputs/OpenGL/ScanTargetGLSLFragments.cpp b/Outputs/OpenGL/ScanTargetGLSLFragments.cpp index fe4abbf1e..e33177639 100644 --- a/Outputs/OpenGL/ScanTargetGLSLFragments.cpp +++ b/Outputs/OpenGL/ScanTargetGLSLFragments.cpp @@ -90,7 +90,7 @@ std::string ScanTarget::glsl_default_vertex_shader(ShaderType type) { if(type == ShaderType::InputScan) { result += "out vec2 textureCoordinate;" - "uniform sampler2D textureName;"; + "uniform usampler2D textureName;"; } else { result += "out vec2 textureCoordinates[15];" @@ -240,7 +240,7 @@ void ScanTarget::enable_vertex_attributes(ShaderType type, Shader &target) { } } -std::unique_ptr ScanTarget::composition_shader() { +std::unique_ptr ScanTarget::composition_shader(InputDataType input_data_type) { /* std::string fragment_shader = "#version 150\n" @@ -350,21 +350,50 @@ std::unique_ptr ScanTarget::composition_shader() { // } - const std::string fragment_shader = + std::string fragment_shader = "#version 150\n" - "in vec2 textureCoordinate;" "out vec4 fragColour;" + "in vec2 textureCoordinate;" - "uniform sampler2D textureName;" + "uniform usampler2D textureName;" - "void main(void) {" - "fragColour = vec4(1.0) - texture(textureName, textureCoordinate);" - "}"; + "void main(void) {"; + + switch(input_data_type) { + case InputDataType::Luminance1: + fragment_shader += "fragColour = texture(textureName, textureCoordinate).rrrr;"; + break; + case InputDataType::Luminance8: + fragment_shader += "fragColour = texture(textureName, textureCoordinate).rrrr / vec4(255.0);"; + break; + + case InputDataType::PhaseLinkedLuminance8: + case InputDataType::Luminance8Phase8: + case InputDataType::Red8Green8Blue8: + fragment_shader += "fragColour = texture(textureName, textureCoordinate) / vec4(255.0);"; + break; + + case InputDataType::Red1Green1Blue1: + fragment_shader += "fragColour = vec4(texture(textureName, textureCoordinate).rrr & uvec3(4u, 2u, 1u), 1.0);"; + break; + + case InputDataType::Red2Green2Blue2: + fragment_shader += + "uint textureValue = texture(textureName, textureCoordinate).r;" + "fragColour = vec4(float((textureValue >> 4) & 3u), float((textureValue >> 2) & 3u), float(textureValue & 3u), 3.0) / 3.0;"; + break; + + case InputDataType::Red4Green4Blue4: + fragment_shader += + "uvec2 textureValue = texture(textureName, textureCoordinate).rg;" + "fragColour = vec4(float(textureValue.r) / 15.0, float(textureValue.g & 240u) / 240.0, float(textureValue.g & 15u) / 15.0, 1.0);"; + break; + } return std::unique_ptr(new Shader( glsl_globals(ShaderType::InputScan) + glsl_default_vertex_shader(ShaderType::InputScan), - fragment_shader, + fragment_shader + "}", attribute_bindings(ShaderType::InputScan) )); }