From 8f6664f0d71218eff4c37e77d900b8c7e3fd4f9f Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 15 Nov 2018 21:02:46 -0500 Subject: [PATCH] Starts towards picking an input shader based on data type and pipeline. --- Machines/Electron/Video.cpp | 6 -- Outputs/CRT/CRT.hpp | 2 - Outputs/OpenGL/ScanTarget.cpp | 42 +++++----- Outputs/OpenGL/ScanTarget.hpp | 6 +- Outputs/OpenGL/ScanTargetGLSLFragments.cpp | 92 +++++++++++++++++++++- Outputs/ScanTarget.hpp | 7 ++ 6 files changed, 122 insertions(+), 33 deletions(-) diff --git a/Machines/Electron/Video.cpp b/Machines/Electron/Video.cpp index 9b07e1b89..3ea5be4d6 100644 --- a/Machines/Electron/Video.cpp +++ b/Machines/Electron/Video.cpp @@ -48,12 +48,6 @@ VideoOutput::VideoOutput(uint8_t *memory) : setup_screen_map(); setup_base_address(); -// crt_->set_rgb_sampling_function( -// "vec3 rgb_sample(usampler2D sampler, vec2 coordinate)" -// "{" -// "uint texValue = texture(sampler, coordinate).r;" -// "return vec3( uvec3(texValue) & uvec3(4u, 2u, 1u));" -// "}"); // TODO: as implied below, I've introduced a clock's latency into the graphics pipeline somehow. Investigate. crt_.set_visible_area(crt_.get_rect_for_area(first_graphics_line - 1, 256, (first_graphics_cycle+1) * crt_cycles_multiplier, 80 * crt_cycles_multiplier, 4.0f / 3.0f)); } diff --git a/Outputs/CRT/CRT.hpp b/Outputs/CRT/CRT.hpp index 3c8b6a46b..5fff3117f 100644 --- a/Outputs/CRT/CRT.hpp +++ b/Outputs/CRT/CRT.hpp @@ -107,8 +107,6 @@ class CRT { in multiples of half a line. @param data_type The format that the caller will use for input data. - - @param scan_target The destination for generated scans. */ CRT(int cycles_per_line, int clocks_per_pixel_greatest_common_divisor, diff --git a/Outputs/OpenGL/ScanTarget.cpp b/Outputs/OpenGL/ScanTarget.cpp index 560a84328..748d9b32d 100644 --- a/Outputs/OpenGL/ScanTarget.cpp +++ b/Outputs/OpenGL/ScanTarget.cpp @@ -89,24 +89,6 @@ ScanTarget::ScanTarget() : glGenTextures(1, &write_area_texture_name_); - input_shader_.reset(new Shader( - glsl_globals(ShaderType::Scan) + glsl_default_vertex_shader(ShaderType::Scan), - "#version 150\n" - - "out vec4 fragColour;" - "in vec2 textureCoordinate;" - - "uniform usampler2D textureName;" - - "void main(void) {" - "fragColour = vec4(float(texture(textureName, textureCoordinate).r), 0.0, 0.0, 1.0);" - "}" - )); - - glBindVertexArray(scan_vertex_array_); - glBindBuffer(GL_ARRAY_BUFFER, scan_buffer_name_); - enable_vertex_attributes(ShaderType::Scan, *input_shader_); - output_shader_.reset(new Shader( glsl_globals(ShaderType::Line) + glsl_default_vertex_shader(ShaderType::Line), "#version 150\n" @@ -160,6 +142,26 @@ void ScanTarget::set_modals(Modals modals) { processing_width_ = colour_cycle_width + (overflow ? dot_clock - overflow : 0); processing_width_ = std::min(processing_width_, 2048); + // Establish an input shader. + input_shader_ = input_shader(modals_.input_data_type, OutputType::RGB); +// input_shader_ = reset(new Shader( +// glsl_globals(ShaderType::Scan) + glsl_default_vertex_shader(ShaderType::Scan), +// "#version 150\n" +// +// "out vec4 fragColour;" +// "in vec2 textureCoordinate;" +// +// "uniform usampler2D textureName;" +// +// "void main(void) {" +// "fragColour = vec4(vec3(texture(textureName, textureCoordinate).rgb), 1.0);" +// "}" +// )); + + glBindVertexArray(scan_vertex_array_); + glBindBuffer(GL_ARRAY_BUFFER, scan_buffer_name_); + enable_vertex_attributes(ShaderType::Scan, *input_shader_); + set_uniforms(Outputs::Display::OpenGL::ScanTarget::ShaderType::Scan, *output_shader_); set_uniforms(Outputs::Display::OpenGL::ScanTarget::ShaderType::Line, *input_shader_); @@ -412,7 +414,7 @@ void ScanTarget::draw(bool synchronous, int output_width, int output_height) { 1 + end_y - start_y, formatForDepth(data_type_size_), GL_UNSIGNED_BYTE, - &write_area_texture_[size_t(TextureAddress(0, start_y))]); + &write_area_texture_[size_t(TextureAddress(0, start_y)) * data_type_size_]); } else { // The circular buffer wrapped around; submit the data from the read pointer to the end of // the buffer and from the start of the buffer to the submit pointer. @@ -429,7 +431,7 @@ void ScanTarget::draw(bool synchronous, int output_width, int output_height) { WriteAreaHeight - start_y, formatForDepth(data_type_size_), GL_UNSIGNED_BYTE, - &write_area_texture_[size_t(TextureAddress(0, start_y))]); + &write_area_texture_[size_t(TextureAddress(0, start_y)) * data_type_size_]); } } diff --git a/Outputs/OpenGL/ScanTarget.hpp b/Outputs/OpenGL/ScanTarget.hpp index c0377a50f..b6d70151b 100644 --- a/Outputs/OpenGL/ScanTarget.hpp +++ b/Outputs/OpenGL/ScanTarget.hpp @@ -123,11 +123,11 @@ class ScanTarget: public Outputs::Display::ScanTarget { from [...]OpenGL::ScanTarget and a vertex function to provide the standard varyings. */ - std::string glsl_globals(ShaderType type); + static std::string glsl_globals(ShaderType type); /*! */ - std::string glsl_default_vertex_shader(ShaderType type); + static std::string glsl_default_vertex_shader(ShaderType type, bool unsigned_sampler = false); /*! Calls @c taret.enable_vertex_attribute_with_pointer to attach all @@ -142,6 +142,8 @@ class ScanTarget: public Outputs::Display::ScanTarget { int processing_width_ = 0; std::unique_ptr input_shader_; std::unique_ptr output_shader_; + + static std::unique_ptr input_shader(InputDataType input_data_type, OutputType output_type); }; } diff --git a/Outputs/OpenGL/ScanTargetGLSLFragments.cpp b/Outputs/OpenGL/ScanTargetGLSLFragments.cpp index 3b10e6a0e..c044e9a62 100644 --- a/Outputs/OpenGL/ScanTargetGLSLFragments.cpp +++ b/Outputs/OpenGL/ScanTargetGLSLFragments.cpp @@ -48,12 +48,13 @@ std::string ScanTarget::glsl_globals(ShaderType type) { } } -std::string ScanTarget::glsl_default_vertex_shader(ShaderType type) { +std::string ScanTarget::glsl_default_vertex_shader(ShaderType type, bool unsigned_sampler) { + const std::string prefix = unsigned_sampler ? "uniform usampler2D textureName;" : "uniform sampler2D textureName;"; switch(type) { case ShaderType::Scan: return + prefix + "out vec2 textureCoordinate;" - "uniform usampler2D textureName;" "void main(void) {" "float lateral = float(gl_VertexID & 1);" @@ -67,8 +68,8 @@ std::string ScanTarget::glsl_default_vertex_shader(ShaderType type) { case ShaderType::Line: return + prefix + "out vec2 textureCoordinate;" - "uniform sampler2D textureName;" "void main(void) {" "float lateral = float(gl_VertexID & 1);" @@ -145,3 +146,88 @@ void ScanTarget::enable_vertex_attributes(ShaderType type, Shader &target) { break; } } + +std::unique_ptr ScanTarget::input_shader(InputDataType input_data_type, OutputType output_type) { + bool unsigned_sampler = false; + std::string fragment_shader = + "#version 150\n" + + "out vec4 fragColour;" + "in vec2 textureCoordinate;"; + + switch(input_data_type) { + case InputDataType::Luminance1: + unsigned_sampler = true; + case InputDataType::Luminance8: + fragment_shader += + unsigned_sampler ? "uniform usampler2D" : "uniform sampler2D"; + + fragment_shader += + " textureName;" + "void main(void) {"; + + switch(output_type) { + case OutputType::RGB: + fragment_shader += "fragColour = vec4(texture(textureName, textureCoordinate).rrr, 1.0);"; + break; + default: + fragment_shader += "fragColour = vec4(texture(textureName, textureCoordinate).r, 0.0, 0.0, 1.0);"; + break; + } + + fragment_shader += "}"; + break; + +// SVideo, +// CompositeColour, +// CompositeMonochrome + + case InputDataType::Phase8Luminance8: + return nullptr; +// fragment_shader += +// "uniform sampler2D textureName;" +// "void main(void) {"; +// +// switch(output_type) { +// default: return nullptr; +// +// case OutputType::SVideo: +// break; +//// CompositeColour, +//// CompositeMonochrome +// } +// +// fragment_shader += "}"; +// break; + + case InputDataType::Red1Green1Blue1: + // TODO: write encoding functions for RGB -> composite/s-video. + unsigned_sampler = true; + fragment_shader += + "uniform usampler2D textureName;" + "void main(void) {" + "uint textureValue = texture(textureName, textureCoordinate).r;" + "fragColour = vec4(uvec3(textureValue) & uvec3(4u, 2u, 1u), 1.0);" + "}"; + break; + + case InputDataType::Red2Green2Blue2: + break; + + case InputDataType::Red4Green4Blue4: + break; + + case InputDataType::Red8Green8Blue8: + fragment_shader += + "uniform sampler2D textureName;" + "void main(void) {" + "fragColour = vec4(texture(textureName, textureCoordinate).rgb, 1.0);" + "}"; + break; + } + + return std::unique_ptr(new Shader( + glsl_globals(ShaderType::Scan) + glsl_default_vertex_shader(ShaderType::Scan, unsigned_sampler), + fragment_shader + )); +} diff --git a/Outputs/ScanTarget.hpp b/Outputs/ScanTarget.hpp index 579583e33..4061a57d1 100644 --- a/Outputs/ScanTarget.hpp +++ b/Outputs/ScanTarget.hpp @@ -48,6 +48,13 @@ enum class ColourSpace { YUV }; +enum class OutputType { + RGB, + SVideo, + CompositeColour, + CompositeMonochrome +}; + /*! Enumerates the potential formats of input data. */