From 6b42b92930965a363ad2215871271f0bf654385e Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 24 Nov 2018 17:37:58 -0500 Subject: [PATCH] Kills CRTOpenGL.cpp and simplifies shader output very slightly. --- .../Clock Signal.xcodeproj/project.pbxproj | 2 - Outputs/OpenGL/CRTOpenGL.cpp | 527 ------------------ Outputs/OpenGL/ScanTarget.cpp | 4 +- Outputs/OpenGL/ScanTargetGLSLFragments.cpp | 56 +- 4 files changed, 30 insertions(+), 559 deletions(-) delete mode 100644 Outputs/OpenGL/CRTOpenGL.cpp diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 7d3ec212e..349708700 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -1369,7 +1369,6 @@ 4BCF1FA31DADC3DD0039D2E7 /* Oric.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Oric.hpp; path = Oric/Oric.hpp; sourceTree = ""; }; 4BD060A51FE49D3C006E14BE /* Speaker.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Speaker.hpp; sourceTree = ""; }; 4BD191D9219113B80042E144 /* OpenGL.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = OpenGL.hpp; sourceTree = ""; }; - 4BD191DC219113B80042E144 /* CRTOpenGL.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CRTOpenGL.cpp; sourceTree = ""; }; 4BD191E0219113B80042E144 /* IntermediateShader.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = IntermediateShader.hpp; sourceTree = ""; }; 4BD191E1219113B80042E144 /* OutputShader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OutputShader.cpp; sourceTree = ""; }; 4BD191E3219113B80042E144 /* IntermediateShader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IntermediateShader.cpp; sourceTree = ""; }; @@ -3027,7 +3026,6 @@ 4BD191D5219113B80042E144 /* OpenGL */ = { isa = PBXGroup; children = ( - 4BD191DC219113B80042E144 /* CRTOpenGL.cpp */, 4BD191F22191180E0042E144 /* ScanTarget.cpp */, 4BD5D2672199148100DDF17D /* ScanTargetGLSLFragments.cpp */, 4BD191D9219113B80042E144 /* OpenGL.hpp */, diff --git a/Outputs/OpenGL/CRTOpenGL.cpp b/Outputs/OpenGL/CRTOpenGL.cpp deleted file mode 100644 index d4739b544..000000000 --- a/Outputs/OpenGL/CRTOpenGL.cpp +++ /dev/null @@ -1,527 +0,0 @@ -// CRTOpenGL.cpp -// Clock Signal -// -// Created by Thomas Harte on 03/02/2016. -// Copyright 2016 Thomas Harte. All rights reserved. -// - -#include "../CRT.hpp" - -#include -#include -#include - -#include "CRTOpenGL.hpp" -#include "../../../SignalProcessing/FIRFilter.hpp" -#include "Shaders/OutputShader.hpp" - -using namespace Outputs::CRT; - -namespace { - static const GLenum source_data_texture_unit = GL_TEXTURE0; - static const GLenum pixel_accumulation_texture_unit = GL_TEXTURE1; - - 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(std::size_t bytes_per_pixel) : - visible_area_(Rect(0, 0, 1, 1)), - composite_src_output_y_(0), - last_output_width_(0), - last_output_height_(0), - fence_(nullptr), - texture_builder(bytes_per_pixel, source_data_texture_unit), - array_builder(SourceVertexBufferDataSize, OutputVertexBufferDataSize) { - glBlendFunc(GL_SRC_ALPHA, GL_CONSTANT_COLOR); - glBlendColor(0.4f, 0.4f, 0.4f, 1.0f); - - // create the output vertex array - glGenVertexArrays(1, &output_vertex_array_); - - // 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(!std::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, 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)); -// } -} - -OpenGLOutputBuilder::~OpenGLOutputBuilder() { - glDeleteVertexArrays(1, &output_vertex_array_); -} - -void OpenGLOutputBuilder::set_target_framebuffer(GLint target_framebuffer) { - target_framebuffer_ = target_framebuffer; -} - -void OpenGLOutputBuilder::draw_frame(unsigned int output_width, unsigned int output_height, bool only_if_dirty) { - // lock down any other draw_frames - draw_mutex_.lock(); - - // establish essentials - if(!output_shader_program_) { - prepare_composite_input_shaders(); - prepare_svideo_input_shaders(); - prepare_rgb_input_shaders(); - prepare_source_vertex_array(); - - prepare_output_shader(); - prepare_output_vertex_array(); - - set_timing_uniforms(); - set_colour_space_uniforms(); - set_gamma(); - } - - if(fence_ != nullptr) { - // if the GPU is still busy, don't wait; we'll catch it next time - if(glClientWaitSync(fence_, GL_SYNC_FLUSH_COMMANDS_BIT, only_if_dirty ? 0 : GL_TIMEOUT_IGNORED) == GL_TIMEOUT_EXPIRED) { - draw_mutex_.unlock(); - return; - } - - glDeleteSync(fence_); - } - - // make sure everything is bound - composite_texture_->bind_texture(); - separated_texture_->bind_texture(); - filtered_texture_->bind_texture(); - if(work_texture_) work_texture_->bind_texture(); - - // make sure there's a target to draw to - if(!framebuffer_ || static_cast(framebuffer_->get_height()) != output_height || static_cast(framebuffer_->get_width()) != output_width) { - 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(); - glClear(GL_COLOR_BUFFER_BIT); - - glActiveTexture(pixel_accumulation_texture_unit); - framebuffer_->bind_texture(); - framebuffer_->draw(static_cast(output_width) / static_cast(output_height)); - - new_framebuffer->bind_texture(); - } - framebuffer_ = std::move(new_framebuffer); - } - - // lock out the machine emulation until data is copied - output_mutex_.lock(); - - // release the mapping, giving up on trying to draw if data has been lost - ArrayBuilder::Submission array_submission = array_builder.submit(); - - // upload new source pixels, if any - glActiveTexture(source_data_texture_unit); - texture_builder.bind(); - texture_builder.submit(); - - // buffer usage restart from 0 for the next time around - composite_src_output_y_ = 0; - - // data having been grabbed, allow the machine to continue - output_mutex_.unlock(); - - struct RenderStage { - 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 - const RenderStage composite_render_stages[] = { - {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, nullptr} - }; - - // for s-video, there are two steps: it's like composite but skips separation - const RenderStage svideo_render_stages[] = { - {svideo_input_shader_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, nullptr} - }; - - // for RGB video, there's also only two steps; a lowpass filter is still applied per physical reality - const RenderStage rgb_render_stages[] = { - {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, nullptr} - }; - - const RenderStage *active_pipeline; - switch(video_signal_) { - default: - case VideoSignal::Composite: active_pipeline = composite_render_stages; break; - case VideoSignal::SVideo: active_pipeline = svideo_render_stages; break; - case VideoSignal::RGB: active_pipeline = rgb_render_stages; break; - } - - if(array_submission.input_size || array_submission.output_size) { - // all drawing will be from the source vertex array and without blending - glBindVertexArray(source_vertex_array_); - glDisable(GL_BLEND); - -#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(); - - if(!work_texture_) { - 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_TRIANGLE_STRIP, 0, 4, (GLsizei)array_submission.input_size / SourceVertexSize); - - active_pipeline++; -#ifdef GL_NV_texture_barrier -// glTextureBarrierNV(); -#endif - } - - // prepare to transfer to framebuffer - framebuffer_->bind_framebuffer(); - - // draw from the output array buffer, with blending - glBindVertexArray(output_vertex_array_); - glEnable(GL_BLEND); - - // update uniforms, then bind the target - if(last_output_width_ != output_width || last_output_height_ != output_height) { - output_shader_program_->set_output_size(output_width, output_height, visible_area_); - last_output_width_ = output_width; - last_output_height_ = output_height; - - // Configure right and left gutters to crop the left- and right-hand 1% of the display. - left_overlay_.reset(new OpenGL::Rectangle(output_shader_program_->get_left_extent() * 0.98f, -1.0f, -1.0f, 2.0f)); - right_overlay_.reset(new OpenGL::Rectangle(output_shader_program_->get_right_extent() * 0.98f, -1.0f, 1.0f, 2.0f)); - } - output_shader_program_->bind(); - - // draw - glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, (GLsizei)array_submission.output_size / OutputVertexSize); - - // mask off the gutter - glDisable(GL_BLEND); - left_overlay_->draw(0.0, 0.0, 0.0); - right_overlay_->draw(0.0, 0.0, 0.0); - } - -#ifdef GL_NV_texture_barrier -// glTextureBarrierNV(); -#endif - - // Copy framebuffer to the intended place; apply a threshold so that any persistent errors in - // the lower part of the colour channels are invisible. - glDisable(GL_BLEND); - glBindFramebuffer(GL_FRAMEBUFFER, static_cast(target_framebuffer_)); - glViewport(0, 0, (GLsizei)output_width, (GLsizei)output_height); - - glActiveTexture(pixel_accumulation_texture_unit); - framebuffer_->bind_texture(); - framebuffer_->draw(static_cast(output_width) / static_cast(output_height), 4.0f / 255.0f); - - fence_ = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); - draw_mutex_.unlock(); -} - -void OpenGLOutputBuilder::reset_all_OpenGL_state() { - composite_input_shader_program_ = nullptr; - composite_separation_filter_program_ = nullptr; - composite_chrominance_filter_shader_program_ = nullptr; - svideo_input_shader_program_ = nullptr; - rgb_input_shader_program_ = nullptr; - rgb_filter_shader_program_ = nullptr; - output_shader_program_ = nullptr; - framebuffer_ = nullptr; - last_output_width_ = last_output_height_ = 0; -} - -void OpenGLOutputBuilder::set_openGL_context_will_change(bool should_delete_resources) { - output_mutex_.lock(); - reset_all_OpenGL_state(); - output_mutex_.unlock(); -} - -void OpenGLOutputBuilder::set_composite_sampling_function(const std::string &shader) { - std::lock_guard lock_guard(output_mutex_); - composite_shader_ = shader; - reset_all_OpenGL_state(); -} - -void OpenGLOutputBuilder::set_svideo_sampling_function(const std::string &shader) { - std::lock_guard lock_guard(output_mutex_); - svideo_shader_ = shader; - reset_all_OpenGL_state(); -} - -void OpenGLOutputBuilder::set_rgb_sampling_function(const std::string &shader) { - std::lock_guard lock_guard(output_mutex_); - rgb_shader_ = shader; - reset_all_OpenGL_state(); -} - -// MARK: - Program compilation - -void OpenGLOutputBuilder::prepare_composite_input_shaders() { - composite_input_shader_program_ = OpenGL::IntermediateShader::make_composite_source_shader(composite_shader_, svideo_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_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_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); - - // TODO: the below is related to texture fencing, which is not yet implemented correctly, so not yet enabled. - 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_svideo_input_shaders() { - if(!svideo_shader_.empty() || !rgb_shader_.empty()) { - svideo_input_shader_program_ = OpenGL::IntermediateShader::make_svideo_source_shader(svideo_shader_, rgb_shader_); - svideo_input_shader_program_->set_source_texture_unit(source_data_texture_unit); - svideo_input_shader_program_->set_output_size(IntermediateBufferWidth, IntermediateBufferHeight); - - // TODO: the below is related to texture fencing, which is not yet implemented correctly, so not yet enabled. - if(work_texture_) { - svideo_input_shader_program_->set_is_double_height(true, 0.0f, 0.0f); - } else { - svideo_input_shader_program_->set_is_double_height(false); - } - } -} - -void OpenGLOutputBuilder::prepare_rgb_input_shaders() { - if(!rgb_shader_.empty()) { - rgb_input_shader_program_ = OpenGL::IntermediateShader::make_rgb_source_shader(rgb_shader_); - rgb_input_shader_program_->set_source_texture_unit(source_data_texture_unit); - rgb_input_shader_program_->set_output_size(IntermediateBufferWidth, IntermediateBufferHeight); - - rgb_filter_shader_program_ = OpenGL::IntermediateShader::make_rgb_filter_shader(); - rgb_filter_shader_program_->set_source_texture_unit(composite_texture_unit); - rgb_filter_shader_program_->set_output_size(IntermediateBufferWidth, IntermediateBufferHeight); - } -} - -void OpenGLOutputBuilder::prepare_source_vertex_array() { - if(composite_input_shader_program_ || svideo_input_shader_program_) { - glBindVertexArray(source_vertex_array_); - array_builder.bind_input(); - } - - using Shader = OpenGL::IntermediateShader; - OpenGL::IntermediateShader *const shaders[] = { - composite_input_shader_program_.get(), - svideo_input_shader_program_.get() - }; - for(int c = 0; c < 2; ++c) { - if(!shaders[c]) continue; - - shaders[c]->enable_vertex_attribute_with_pointer( - Shader::get_input_name(Shader::Input::InputStart), - 2, GL_UNSIGNED_SHORT, GL_FALSE, SourceVertexSize, - (void *)SourceVertexOffsetOfInputStart, 1); - - shaders[c]->enable_vertex_attribute_with_pointer( - Shader::get_input_name(Shader::Input::OutputStart), - 2, GL_UNSIGNED_SHORT, GL_FALSE, SourceVertexSize, - (void *)SourceVertexOffsetOfOutputStart, 1); - - shaders[c]->enable_vertex_attribute_with_pointer( - Shader::get_input_name(Shader::Input::Ends), - 2, GL_UNSIGNED_SHORT, GL_FALSE, SourceVertexSize, - (void *)SourceVertexOffsetOfEnds, 1); - - shaders[c]->enable_vertex_attribute_with_pointer( - Shader::get_input_name(Shader::Input::PhaseTimeAndAmplitude), - 3, GL_UNSIGNED_BYTE, GL_FALSE, SourceVertexSize, - (void *)SourceVertexOffsetOfPhaseTimeAndAmplitude, 1); - } -} - -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_); -} - -void OpenGLOutputBuilder::prepare_output_vertex_array() { - if(output_shader_program_) { - glBindVertexArray(output_vertex_array_); - array_builder.bind_output(); - - using Shader = OpenGL::OutputShader; - output_shader_program_->enable_vertex_attribute_with_pointer( - Shader::get_input_name(Shader::Input::Horizontal), - 2, GL_UNSIGNED_SHORT, GL_FALSE, OutputVertexSize, - (void *)OutputVertexOffsetOfHorizontal, 1); - - output_shader_program_->enable_vertex_attribute_with_pointer( - Shader::get_input_name(Shader::Input::Vertical), - 2, GL_UNSIGNED_SHORT, GL_FALSE, OutputVertexSize, - (void *)OutputVertexOffsetOfVertical, 1); - } -} - -// MARK: - Public Configuration - -void OpenGLOutputBuilder::set_video_signal(VideoSignal video_signal) { - if(video_signal_ != video_signal) { - video_signal_ = video_signal; - composite_src_output_y_ = 0; - last_output_width_ = 0; - last_output_height_ = 0; - set_output_shader_width(); - } -} - -void OpenGLOutputBuilder::set_timing(unsigned int input_frequency, unsigned int cycles_per_line, unsigned int height_of_display, unsigned int horizontal_scan_period, unsigned int vertical_scan_period, unsigned int vertical_period_divider) { - std::lock_guard lock_guard(output_mutex_); - input_frequency_ = input_frequency; - cycles_per_line_ = cycles_per_line; - height_of_display_ = height_of_display; - horizontal_scan_period_ = horizontal_scan_period; - vertical_scan_period_ = vertical_scan_period; - vertical_period_divider_ = vertical_period_divider; - - set_timing_uniforms(); -} - -// MARK: - Internal Configuration - -void OpenGLOutputBuilder::set_colour_space_uniforms() { - GLfloat rgbToYUV[] = {0.299f, -0.14713f, 0.615f, 0.587f, -0.28886f, -0.51499f, 0.114f, 0.436f, -0.10001f}; - GLfloat yuvToRGB[] = {1.0f, 1.0f, 1.0f, 0.0f, -0.39465f, 2.03211f, 1.13983f, -0.58060f, 0.0f}; - - GLfloat rgbToYIQ[] = {0.299f, 0.596f, 0.211f, 0.587f, -0.274f, -0.523f, 0.114f, -0.322f, 0.312f}; - GLfloat yiqToRGB[] = {1.0f, 1.0f, 1.0f, 0.956f, -0.272f, -1.106f, 0.621f, -0.647f, 1.703f}; - - GLfloat *fromRGB = nullptr, *toRGB = nullptr; - - switch(colour_space_) { - case ColourSpace::YIQ: - fromRGB = rgbToYIQ; - toRGB = yiqToRGB; - break; - - case ColourSpace::YUV: - fromRGB = rgbToYUV; - toRGB = yuvToRGB; - break; - - default: assert(false); break; - } - - 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); - if(svideo_input_shader_program_) svideo_input_shader_program_->set_colour_conversion_matrices(fromRGB, toRGB); -} - -void OpenGLOutputBuilder::set_gamma() { - if(output_shader_program_) output_shader_program_->set_gamma_ratio(gamma_); -} - -/*! - @returns The multiplier to apply to x positions received at the shader in order to produce locations in the intermediate - texture. Intermediate textures are in phase with the composite signal, so this is a function of (i) composite frequency - (determining how much of the texture adds up to a single line); and (ii) input frequency (determining what the input - positions mean as a fraction of a line). -*/ -float OpenGLOutputBuilder::get_composite_output_width() const { - return - (static_cast(colour_cycle_numerator_ * 4) / static_cast(colour_cycle_denominator_ * IntermediateBufferWidth)) * - (static_cast(IntermediateBufferWidth) / static_cast(cycles_per_line_)); -} - -void OpenGLOutputBuilder::set_output_shader_width() { - if(output_shader_program_) { - // For anything that isn't RGB, scale so that sampling is in-phase with the colour subcarrier. - const float width = (video_signal_ == VideoSignal::RGB) ? 1.0f : get_composite_output_width(); - output_shader_program_->set_input_width_scaler(width); - } -} - -void OpenGLOutputBuilder::set_timing_uniforms() { - const float colour_subcarrier_frequency = static_cast(colour_cycle_numerator_) / static_cast(colour_cycle_denominator_); - const float output_width = get_composite_output_width(); - const 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(sample_cycles_per_line, colour_subcarrier_frequency); - 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_extension(5.0f); - } - if(rgb_filter_shader_program_) { - rgb_filter_shader_program_->set_width_scalers(1.0f, 1.0f); - rgb_filter_shader_program_->set_filter_coefficients(sample_cycles_per_line, static_cast(input_frequency_) * 0.5f); - } - if(output_shader_program_) { - 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_) { - composite_input_shader_program_->set_width_scalers(1.0f, output_width); - composite_input_shader_program_->set_extension(0.0f); - } - if(svideo_input_shader_program_) { - svideo_input_shader_program_->set_width_scalers(1.0f, output_width); - svideo_input_shader_program_->set_extension(0.0f); - } - if(rgb_input_shader_program_) { - rgb_input_shader_program_->set_width_scalers(1.0f, 1.0f); - } -} diff --git a/Outputs/OpenGL/ScanTarget.cpp b/Outputs/OpenGL/ScanTarget.cpp index 5363741a3..9533738cb 100644 --- a/Outputs/OpenGL/ScanTarget.cpp +++ b/Outputs/OpenGL/ScanTarget.cpp @@ -13,7 +13,6 @@ using namespace Outputs::Display::OpenGL; namespace { - /// The texture unit from which to source 1bpp input data. constexpr GLenum SourceData1BppTextureUnit = GL_TEXTURE0; /// The texture unit from which to source 2bpp input data. @@ -175,6 +174,7 @@ void ScanTarget::set_modals(Modals modals) { // Cascade the texture units in use as per the pipeline stages. std::vector input_shaders = {input_shader_.get()}; GLint texture_unit = GLint(UnprocessedLineBufferTextureUnit - GL_TEXTURE0); +// output_shader_->set_uniform("textureName", texture_unit); for(const auto &stage: pipeline_stages_) { input_shaders.push_back(stage.shader.get()); @@ -186,8 +186,6 @@ void ScanTarget::set_modals(Modals modals) { } output_shader_->set_uniform("textureName", texture_unit); -// enable_vertex_attributes(ShaderType::InputScan, *input_shader_); - // Ensure that all shaders involved in the input pipeline have the proper colour space knowledged. for(auto shader: input_shaders) { switch(modals.composite_colour_space) { diff --git a/Outputs/OpenGL/ScanTargetGLSLFragments.cpp b/Outputs/OpenGL/ScanTargetGLSLFragments.cpp index 51fbdf772..c0c0a2626 100644 --- a/Outputs/OpenGL/ScanTargetGLSLFragments.cpp +++ b/Outputs/OpenGL/ScanTargetGLSLFragments.cpp @@ -110,23 +110,25 @@ std::string ScanTarget::glsl_default_vertex_shader(ShaderType type) { if(type == ShaderType::InputScan) { result += - "textureCoordinate = vec2(mix(startDataX, endDataX, lateral), dataY) / textureSize(textureName, 0);" // TODO: dataY + 0.5 + "textureCoordinate = vec2(mix(startDataX, endDataX, lateral), dataY + 0.5) / textureSize(textureName, 0);" "vec2 eyePosition = vec2(mix(startPoint.x, endPoint.x, lateral) * processingWidth, lineY + longitudinal) / vec2(scale.x, 2048.0);"; } else { result += - "vec2 eyePosition = vec2(mix(startPoint.x, endPoint.x, lateral) * processingWidth, lineY + longitudinal) / vec2(scale.x, 2048.0);" + "vec2 sourcePosition = vec2(mix(startPoint.x, endPoint.x, lateral) * processingWidth, lineY + 0.5);" + "vec2 eyePosition = (sourcePosition + vec2(0.0, longitudinal - 0.5)) / vec2(scale.x, 2048.0);" + "sourcePosition /= vec2(scale.x, 2048.0);" - "textureCoordinates[0] = eyePosition + vec2(-5.0, 0.0) / textureSize(textureName, 0);" - "textureCoordinates[1] = eyePosition + vec2(-4.0, 0.0) / textureSize(textureName, 0);" - "textureCoordinates[2] = eyePosition + vec2(-3.0, 0.0) / textureSize(textureName, 0);" - "textureCoordinates[3] = eyePosition + vec2(-2.0, 0.0) / textureSize(textureName, 0);" - "textureCoordinates[4] = eyePosition + vec2(-1.0, 0.0) / textureSize(textureName, 0);" - "textureCoordinates[5] = eyePosition;" - "textureCoordinates[6] = eyePosition + vec2(1.0, 0.0) / textureSize(textureName, 0);" - "textureCoordinates[7] = eyePosition + vec2(2.0, 0.0) / textureSize(textureName, 0);" - "textureCoordinates[8] = eyePosition + vec2(3.0, 0.0) / textureSize(textureName, 0);" - "textureCoordinates[9] = eyePosition + vec2(4.0, 0.0) / textureSize(textureName, 0);" - "textureCoordinates[10] = eyePosition + vec2(5.0, 0.0) / textureSize(textureName, 0);" + "textureCoordinates[0] = sourcePosition + vec2(-5.0, 0.0) / textureSize(textureName, 0);" + "textureCoordinates[1] = sourcePosition + vec2(-4.0, 0.0) / textureSize(textureName, 0);" + "textureCoordinates[2] = sourcePosition + vec2(-3.0, 0.0) / textureSize(textureName, 0);" + "textureCoordinates[3] = sourcePosition + vec2(-2.0, 0.0) / textureSize(textureName, 0);" + "textureCoordinates[4] = sourcePosition + vec2(-1.0, 0.0) / textureSize(textureName, 0);" + "textureCoordinates[5] = sourcePosition;" + "textureCoordinates[6] = sourcePosition + vec2(1.0, 0.0) / textureSize(textureName, 0);" + "textureCoordinates[7] = sourcePosition + vec2(2.0, 0.0) / textureSize(textureName, 0);" + "textureCoordinates[8] = sourcePosition + vec2(3.0, 0.0) / textureSize(textureName, 0);" + "textureCoordinates[9] = sourcePosition + vec2(4.0, 0.0) / textureSize(textureName, 0);" + "textureCoordinates[10] = sourcePosition + vec2(5.0, 0.0) / textureSize(textureName, 0);" "eyePosition = eyePosition;"; } @@ -155,7 +157,6 @@ std::string ScanTarget::glsl_default_vertex_shader(ShaderType type) { } void ScanTarget::enable_vertex_attributes(ShaderType type, Shader &target) { - target.bind(); switch(type) { case ShaderType::InputScan: case ShaderType::ProcessedScan: @@ -228,7 +229,7 @@ std::unique_ptr ScanTarget::input_shader(InputDataType input_data_type, std::string fragment_shader = "#version 150\n" - "out vec4 fragColour;" + "out vec3 fragColour;" "in vec2 textureCoordinate;" "in float compositeAngle;" "in float compositeAmplitudeOut;" @@ -243,12 +244,12 @@ std::unique_ptr ScanTarget::input_shader(InputDataType input_data_type, switch(input_data_type) { case InputDataType::Luminance1: computed_display_type = DisplayType::CompositeMonochrome; - fragment_shader += "fragColour = vec4(vec3(texture(textureName, textureCoordinate).r), 1.0);"; + fragment_shader += "fragColour = texture(textureName, textureCoordinate).rrr;"; break; case InputDataType::Luminance8: computed_display_type = DisplayType::CompositeMonochrome; - fragment_shader += "fragColour = vec4(vec3(texture(textureName, textureCoordinate).r / 255.0), 1.0);"; + fragment_shader += "fragColour = vec3(texture(textureName, textureCoordinate).r / 255.0);"; break; case InputDataType::Luminance8Phase8: @@ -258,33 +259,33 @@ std::unique_ptr ScanTarget::input_shader(InputDataType input_data_type, "float phaseOffset = 3.141592654 * 2.0 * 2.0 * yc.y;" "float chroma = step(yc.y, 0.75) * cos(compositeAngle + phaseOffset);" - "fragColour = vec4(yc.x, chroma, 0.0, 1.0);"; + "fragColour = vec3(yc.x, chroma, 0.0);"; break; case InputDataType::Red1Green1Blue1: computed_display_type = DisplayType::RGB; fragment_shader += "uint textureValue = texture(textureName, textureCoordinate).r;" - "fragColour = vec4(uvec3(textureValue) & uvec3(4u, 2u, 1u), 1.0);"; + "fragColour = uvec3(textureValue) & uvec3(4u, 2u, 1u);"; break; case InputDataType::Red2Green2Blue2: computed_display_type = DisplayType::RGB; fragment_shader += "uint textureValue = texture(textureName, textureCoordinate).r;" - "fragColour = vec4(vec3(float((textureValue >> 4) & 3u), float((textureValue >> 2) & 3u), float(textureValue & 3u)) / 3.0, 1.0);"; + "fragColour = vec3(float((textureValue >> 4) & 3u), float((textureValue >> 2) & 3u), float(textureValue & 3u)) / 3.0;"; break; case InputDataType::Red4Green4Blue4: computed_display_type = DisplayType::RGB; 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);"; + "fragColour = vec3(float(textureValue.r) / 15.0, float(textureValue.g & 240u) / 240.0, float(textureValue.g & 15u) / 15.0);"; break; case InputDataType::Red8Green8Blue8: computed_display_type = DisplayType::RGB; - fragment_shader += "fragColour = vec4(texture(textureName, textureCoordinate).rgb / vec3(255.0), 1.0);"; + fragment_shader += "fragColour = texture(textureName, textureCoordinate).rgb / vec3(255.0);"; break; } @@ -293,14 +294,14 @@ std::unique_ptr ScanTarget::input_shader(InputDataType input_data_type, // there'll definitely be an RGB to SVideo step. if(computed_display_type == DisplayType::RGB) { fragment_shader += - "vec3 composite_colour = rgbToLumaChroma * vec3(fragColour);" + "vec3 composite_colour = rgbToLumaChroma * fragColour;" "vec2 quadrature = vec2(cos(compositeAngle), sin(compositeAngle));" - "fragColour = vec4(composite_colour.r, 0.5 + dot(quadrature, composite_colour.gb)*0.5, 0.0, 1.0);"; + "fragColour = vec3(composite_colour.r, 0.5 + dot(quadrature, composite_colour.gb)*0.5, 0.0);"; } // If the output type isn't SVideo, add an SVideo to composite step. if(display_type != DisplayType::SVideo) { - fragment_shader += "fragColour = vec4(vec3(mix(fragColour.r, 2.0*(fragColour.g - 0.5), compositeAmplitudeOut)), 1.0);"; + fragment_shader += "fragColour = vec3(mix(fragColour.r, 2.0*(fragColour.g - 0.5), compositeAmplitudeOut));"; } } @@ -331,9 +332,10 @@ std::unique_ptr ScanTarget::svideo_to_rgb_shader(int colour_cycle_numera "uniform float textureWeights[11];" "uniform usampler2D textureName;" - "out vec4 fragColour;" + "out vec3 fragColour;" "void main(void) {" - "fragColour = texture(textureName, textureCoordinates[5]);" + "vec3 textureSample = vec3(texture(textureName, textureCoordinates[5]).rgb) / vec3(65536.0 * 16384.0);" + "fragColour = textureSample;" "}", attribute_bindings(ShaderType::ProcessedScan) ));