diff --git a/Components/6560/6560.hpp b/Components/6560/6560.hpp index 169690c00..23bb6e4d1 100644 --- a/Components/6560/6560.hpp +++ b/Components/6560/6560.hpp @@ -69,7 +69,7 @@ template class MOS6560 { speaker_(audio_generator_) { crt_->set_svideo_sampling_function( - "vec2 svideo_sample(usampler2D texID, vec2 coordinate, vec2 iCoordinate, float phase, float amplitude)" + "vec2 svideo_sample(usampler2D texID, vec2 coordinate, float phase, float amplitude)" "{" "vec2 yc = texture(texID, coordinate).rg / vec2(255.0);" diff --git a/Components/9918/9918.cpp b/Components/9918/9918.cpp index c16f3735f..c64bbac72 100644 --- a/Components/9918/9918.cpp +++ b/Components/9918/9918.cpp @@ -92,7 +92,7 @@ TMS9918::TMS9918(Personality p) { // Unimaginatively, this class just passes RGB through to the shader. Investigation is needed // into whether there's a more natural form. crt_->set_rgb_sampling_function( - "vec3 rgb_sample(usampler2D sampler, vec2 coordinate, vec2 icoordinate)" + "vec3 rgb_sample(usampler2D sampler, vec2 coordinate)" "{" "return texture(sampler, coordinate).rgb / vec3(255.0);" "}"); diff --git a/Machines/AmstradCPC/AmstradCPC.cpp b/Machines/AmstradCPC/AmstradCPC.cpp index 92d146720..a6a8a20f9 100644 --- a/Machines/AmstradCPC/AmstradCPC.cpp +++ b/Machines/AmstradCPC/AmstradCPC.cpp @@ -327,7 +327,7 @@ class CRTCBusHandler { void setup_output(float aspect_ratio) { crt_.reset(new Outputs::CRT::CRT(1024, 16, Outputs::CRT::DisplayType::PAL50, 1)); crt_->set_rgb_sampling_function( - "vec3 rgb_sample(usampler2D sampler, vec2 coordinate, vec2 icoordinate)" + "vec3 rgb_sample(usampler2D sampler, vec2 coordinate)" "{" "uint sample = texture(texID, coordinate).r;" "return vec3(float((sample >> 4) & 3u), float((sample >> 2) & 3u), float(sample & 3u)) / 2.0;" diff --git a/Machines/AppleII/Video.cpp b/Machines/AppleII/Video.cpp index 11051188d..c65117f9f 100644 --- a/Machines/AppleII/Video.cpp +++ b/Machines/AppleII/Video.cpp @@ -18,7 +18,7 @@ VideoBase::VideoBase(bool is_iie, std::function &&target) : // Set a composite sampling function that assumes one byte per pixel input, and // accepts any non-zero value as being fully on, zero being fully off. crt_->set_composite_sampling_function( - "float composite_sample(usampler2D sampler, vec2 coordinate, vec2 icoordinate, float phase, float amplitude)" + "float composite_sample(usampler2D sampler, vec2 coordinate, float phase, float amplitude)" "{" "return clamp(texture(sampler, coordinate).r, 0.0, 1.0);" "}"); diff --git a/Machines/Atari2600/TIA.cpp b/Machines/Atari2600/TIA.cpp index af37c49f9..2d540e97a 100644 --- a/Machines/Atari2600/TIA.cpp +++ b/Machines/Atari2600/TIA.cpp @@ -124,7 +124,7 @@ void TIA::set_output_mode(Atari2600::TIA::OutputMode output_mode) { if(output_mode == OutputMode::NTSC) { crt_->set_svideo_sampling_function( - "vec2 svideo_sample(usampler2D texID, vec2 coordinate, vec2 iCoordinate, float phase, float amplitude)" + "vec2 svideo_sample(usampler2D texID, vec2 coordinate, float phase, float amplitude)" "{" "uint c = texture(texID, coordinate).r;" "uint y = c & 14u;" @@ -136,7 +136,7 @@ void TIA::set_output_mode(Atari2600::TIA::OutputMode output_mode) { display_type = Outputs::CRT::DisplayType::NTSC60; } else { crt_->set_svideo_sampling_function( - "vec2 svideo_sample(usampler2D texID, vec2 coordinate, vec2 iCoordinate, float phase, float amplitude)" + "vec2 svideo_sample(usampler2D texID, vec2 coordinate, float phase, float amplitude)" "{" "uint c = texture(texID, coordinate).r;" "uint y = c & 14u;" diff --git a/Machines/Electron/Video.cpp b/Machines/Electron/Video.cpp index 2d7b316af..82cabd225 100644 --- a/Machines/Electron/Video.cpp +++ b/Machines/Electron/Video.cpp @@ -34,13 +34,6 @@ namespace { static const int real_time_clock_interrupt_2 = 56704; static const int display_end_interrupt_1 = (first_graphics_line + display_end_interrupt_line)*cycles_per_line; static const int display_end_interrupt_2 = (first_graphics_line + field_divider_line + display_end_interrupt_line)*cycles_per_line; - - struct FourBPPBookender: public Outputs::CRT::TextureBuilder::Bookender { - void add_bookends(uint8_t *const left_value, uint8_t *const right_value, uint8_t *left_bookend, uint8_t *right_bookend) { - *left_bookend = static_cast(((*left_value) & 0x0f) | (((*left_value) & 0x0f) << 4)); - *right_bookend = static_cast(((*right_value) & 0xf0) | (((*right_value) & 0xf0) >> 4)); - } - }; } // MARK: - Lifecycle @@ -52,15 +45,11 @@ VideoOutput::VideoOutput(uint8_t *memory) : ram_(memory) { crt_.reset(new Outputs::CRT::CRT(crt_cycles_per_line, 8, Outputs::CRT::DisplayType::PAL50, 1)); crt_->set_rgb_sampling_function( - "vec3 rgb_sample(usampler2D sampler, vec2 coordinate, vec2 icoordinate)" + "vec3 rgb_sample(usampler2D sampler, vec2 coordinate)" "{" "uint texValue = texture(sampler, coordinate).r;" - "texValue >>= 4 - (int(icoordinate.x) & 4);" "return vec3( uvec3(texValue) & uvec3(4u, 2u, 1u));" "}"); - crt_->set_integer_coordinate_multiplier(8.0f); - std::unique_ptr bookender(new FourBPPBookender); - crt_->set_bookender(std::move(bookender)); // 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)); } @@ -113,9 +102,9 @@ void VideoOutput::output_pixels(unsigned int number_of_cycles) { } else { unsigned int divider = 1; switch(screen_mode_) { - case 0: case 3: divider = 2; break; - case 1: case 4: case 6: divider = 4; break; - case 2: case 5: divider = 8; break; + case 0: case 3: divider = 1; break; + case 1: case 4: case 6: divider = 2; break; + case 2: case 5: divider = 4; break; } if(!initial_output_target_ || divider != current_output_divider_) { @@ -124,7 +113,7 @@ void VideoOutput::output_pixels(unsigned int number_of_cycles) { crt_->output_data(data_length * current_output_divider_, data_length); } current_output_divider_ = divider; - initial_output_target_ = current_output_target_ = crt_->allocate_write_area(640 / current_output_divider_, 4); + initial_output_target_ = current_output_target_ = crt_->allocate_write_area(640 / current_output_divider_, 8 / divider); } #define get_pixel() \ @@ -139,8 +128,8 @@ void VideoOutput::output_pixels(unsigned int number_of_cycles) { if(initial_output_target_) { while(number_of_cycles--) { get_pixel(); - *reinterpret_cast(current_output_target_) = palette_tables_.eighty1bpp[last_pixel_byte_]; - current_output_target_ += 4; + *reinterpret_cast(current_output_target_) = palette_tables_.eighty1bpp[last_pixel_byte_]; + current_output_target_ += 8; current_pixel_column_++; } } else current_output_target_ += 4*number_of_cycles; @@ -150,8 +139,8 @@ void VideoOutput::output_pixels(unsigned int number_of_cycles) { if(initial_output_target_) { while(number_of_cycles--) { get_pixel(); - *reinterpret_cast(current_output_target_) = palette_tables_.eighty2bpp[last_pixel_byte_]; - current_output_target_ += 2; + *reinterpret_cast(current_output_target_) = palette_tables_.eighty2bpp[last_pixel_byte_]; + current_output_target_ += 4; current_pixel_column_++; } } else current_output_target_ += 2*number_of_cycles; @@ -161,8 +150,8 @@ void VideoOutput::output_pixels(unsigned int number_of_cycles) { if(initial_output_target_) { while(number_of_cycles--) { get_pixel(); - *current_output_target_ = palette_tables_.eighty4bpp[last_pixel_byte_]; - current_output_target_ += 1; + *reinterpret_cast(current_output_target_) = palette_tables_.eighty4bpp[last_pixel_byte_]; + current_output_target_ += 2; current_pixel_column_++; } } else current_output_target_ += number_of_cycles; @@ -172,28 +161,28 @@ void VideoOutput::output_pixels(unsigned int number_of_cycles) { if(initial_output_target_) { if(current_pixel_column_&1) { last_pixel_byte_ <<= 4; - *reinterpret_cast(current_output_target_) = palette_tables_.forty1bpp[last_pixel_byte_]; - current_output_target_ += 2; + *reinterpret_cast(current_output_target_) = palette_tables_.forty1bpp[last_pixel_byte_]; + current_output_target_ += 4; number_of_cycles--; current_pixel_column_++; } while(number_of_cycles > 1) { get_pixel(); - *reinterpret_cast(current_output_target_) = palette_tables_.forty1bpp[last_pixel_byte_]; - current_output_target_ += 2; + *reinterpret_cast(current_output_target_) = palette_tables_.forty1bpp[last_pixel_byte_]; + current_output_target_ += 4; last_pixel_byte_ <<= 4; - *reinterpret_cast(current_output_target_) = palette_tables_.forty1bpp[last_pixel_byte_]; - current_output_target_ += 2; + *reinterpret_cast(current_output_target_) = palette_tables_.forty1bpp[last_pixel_byte_]; + current_output_target_ += 4; number_of_cycles -= 2; current_pixel_column_+=2; } if(number_of_cycles) { get_pixel(); - *reinterpret_cast(current_output_target_) = palette_tables_.forty1bpp[last_pixel_byte_]; - current_output_target_ += 2; + *reinterpret_cast(current_output_target_) = palette_tables_.forty1bpp[last_pixel_byte_]; + current_output_target_ += 4; current_pixel_column_++; } } else current_output_target_ += 2 * number_of_cycles; @@ -203,28 +192,28 @@ void VideoOutput::output_pixels(unsigned int number_of_cycles) { if(initial_output_target_) { if(current_pixel_column_&1) { last_pixel_byte_ <<= 2; - *current_output_target_ = palette_tables_.forty2bpp[last_pixel_byte_]; - current_output_target_ += 1; + *reinterpret_cast(current_output_target_) = palette_tables_.forty2bpp[last_pixel_byte_]; + current_output_target_ += 2; number_of_cycles--; current_pixel_column_++; } while(number_of_cycles > 1) { get_pixel(); - *current_output_target_ = palette_tables_.forty2bpp[last_pixel_byte_]; - current_output_target_ += 1; + *reinterpret_cast(current_output_target_) = palette_tables_.forty2bpp[last_pixel_byte_]; + current_output_target_ += 2; last_pixel_byte_ <<= 2; - *current_output_target_ = palette_tables_.forty2bpp[last_pixel_byte_]; - current_output_target_ += 1; + *reinterpret_cast(current_output_target_) = palette_tables_.forty2bpp[last_pixel_byte_]; + current_output_target_ += 2; number_of_cycles -= 2; current_pixel_column_+=2; } if(number_of_cycles) { get_pixel(); - *current_output_target_ = palette_tables_.forty2bpp[last_pixel_byte_]; - current_output_target_ += 1; + *reinterpret_cast(current_output_target_) = palette_tables_.forty2bpp[last_pixel_byte_]; + current_output_target_ += 2; current_pixel_column_++; } } else current_output_target_ += number_of_cycles; @@ -310,27 +299,37 @@ void VideoOutput::set_register(int address, uint8_t value) { } // regenerate all palette tables for now -#define pack(a, b) static_cast((a << 4) | (b)) for(int byte = 0; byte < 256; byte++) { uint8_t *target = reinterpret_cast(&palette_tables_.forty1bpp[byte]); - target[0] = pack(palette_[(byte&0x80) >> 4], palette_[(byte&0x40) >> 3]); - target[1] = pack(palette_[(byte&0x20) >> 2], palette_[(byte&0x10) >> 1]); + target[0] = palette_[(byte&0x80) >> 4]; + target[1] = palette_[(byte&0x40) >> 3]; + target[2] = palette_[(byte&0x20) >> 2]; + target[3] = palette_[(byte&0x10) >> 1]; target = reinterpret_cast(&palette_tables_.eighty2bpp[byte]); - target[0] = pack(palette_[((byte&0x80) >> 4) | ((byte&0x08) >> 2)], palette_[((byte&0x40) >> 3) | ((byte&0x04) >> 1)]); - target[1] = pack(palette_[((byte&0x20) >> 2) | ((byte&0x02) >> 0)], palette_[((byte&0x10) >> 1) | ((byte&0x01) << 1)]); + target[0] = palette_[((byte&0x80) >> 4) | ((byte&0x08) >> 2)]; + target[1] = palette_[((byte&0x40) >> 3) | ((byte&0x04) >> 1)]; + target[2] = palette_[((byte&0x20) >> 2) | ((byte&0x02) >> 0)]; + target[3] = palette_[((byte&0x10) >> 1) | ((byte&0x01) << 1)]; target = reinterpret_cast(&palette_tables_.eighty1bpp[byte]); - target[0] = pack(palette_[(byte&0x80) >> 4], palette_[(byte&0x40) >> 3]); - target[1] = pack(palette_[(byte&0x20) >> 2], palette_[(byte&0x10) >> 1]); - target[2] = pack(palette_[(byte&0x08) >> 0], palette_[(byte&0x04) << 1]); - target[3] = pack(palette_[(byte&0x02) << 2], palette_[(byte&0x01) << 3]); + target[0] = palette_[(byte&0x80) >> 4]; + target[1] = palette_[(byte&0x40) >> 3]; + target[2] = palette_[(byte&0x20) >> 2]; + target[3] = palette_[(byte&0x10) >> 1]; + target[4] = palette_[(byte&0x08) >> 0]; + target[5] = palette_[(byte&0x04) << 1]; + target[6] = palette_[(byte&0x02) << 2]; + target[7] = palette_[(byte&0x01) << 3]; - palette_tables_.forty2bpp[byte] = pack( palette_[((byte&0x80) >> 4) | ((byte&0x08) >> 2)], palette_[((byte&0x40) >> 3) | ((byte&0x04) >> 1)]); - palette_tables_.eighty4bpp[byte] = pack( palette_[((byte&0x80) >> 4) | ((byte&0x20) >> 3) | ((byte&0x08) >> 2) | ((byte&0x02) >> 1)], - palette_[((byte&0x40) >> 3) | ((byte&0x10) >> 2) | ((byte&0x04) >> 1) | ((byte&0x01) >> 0)]); + target = reinterpret_cast(&palette_tables_.forty2bpp[byte]); + target[0] = palette_[((byte&0x80) >> 4) | ((byte&0x08) >> 2)]; + target[1] = palette_[((byte&0x40) >> 3) | ((byte&0x04) >> 1)]; + + target = reinterpret_cast(&palette_tables_.eighty4bpp[byte]); + target[0] = palette_[((byte&0x80) >> 4) | ((byte&0x20) >> 3) | ((byte&0x08) >> 2) | ((byte&0x02) >> 1)]; + target[1] = palette_[((byte&0x40) >> 3) | ((byte&0x10) >> 2) | ((byte&0x04) >> 1) | ((byte&0x01) >> 0)]; } -#undef pack } break; } diff --git a/Machines/Electron/Video.hpp b/Machines/Electron/Video.hpp index 0a4db2eab..04aa939f2 100644 --- a/Machines/Electron/Video.hpp +++ b/Machines/Electron/Video.hpp @@ -90,11 +90,11 @@ class VideoOutput { uint8_t *ram_; struct { - uint16_t forty1bpp[256]; - uint8_t forty2bpp[256]; - uint32_t eighty1bpp[256]; - uint16_t eighty2bpp[256]; - uint8_t eighty4bpp[256]; + uint32_t forty1bpp[256]; + uint16_t forty2bpp[256]; + uint64_t eighty1bpp[256]; + uint32_t eighty2bpp[256]; + uint16_t eighty4bpp[256]; } palette_tables_; // Display generation. diff --git a/Machines/Oric/Video.cpp b/Machines/Oric/Video.cpp index 9022e14a5..e28d7cfe0 100644 --- a/Machines/Oric/Video.cpp +++ b/Machines/Oric/Video.cpp @@ -25,13 +25,13 @@ VideoOutput::VideoOutput(uint8_t *memory) : v_sync_start_position_(PAL50VSyncStartPosition), v_sync_end_position_(PAL50VSyncEndPosition), counter_period_(PAL50Period) { crt_->set_rgb_sampling_function( - "vec3 rgb_sample(usampler2D sampler, vec2 coordinate, vec2 icoordinate)" + "vec3 rgb_sample(usampler2D sampler, vec2 coordinate)" "{" "uint texValue = texture(sampler, coordinate).r;" "return vec3( uvec3(texValue) & uvec3(4u, 2u, 1u));" "}"); crt_->set_composite_sampling_function( - "float composite_sample(usampler2D sampler, vec2 coordinate, vec2 icoordinate, float phase, float amplitude)" + "float composite_sample(usampler2D sampler, vec2 coordinate, float phase, float amplitude)" "{" "uint texValue = uint(dot(texture(sampler, coordinate).rg, uvec2(1, 256)));" "uint iPhase = uint((phase + 3.141592654 + 0.39269908175) * 2.0 / 3.141592654) & 3u;" diff --git a/Machines/ZX8081/Video.cpp b/Machines/ZX8081/Video.cpp index 95e691301..ce2fcbc55 100644 --- a/Machines/ZX8081/Video.cpp +++ b/Machines/ZX8081/Video.cpp @@ -26,7 +26,7 @@ Video::Video() : // Set a composite sampling function that assumes two-level input; either a byte is 0, which is black, // or it is non-zero, which is white. crt_->set_composite_sampling_function( - "float composite_sample(usampler2D sampler, vec2 coordinate, vec2 icoordinate, float phase, float amplitude)" + "float composite_sample(usampler2D sampler, vec2 coordinate, float phase, float amplitude)" "{" "return texture(sampler, coordinate).r;" "}"); diff --git a/Outputs/CRT/CRT.hpp b/Outputs/CRT/CRT.hpp index c27fa86e5..83f889c50 100644 --- a/Outputs/CRT/CRT.hpp +++ b/Outputs/CRT/CRT.hpp @@ -280,7 +280,7 @@ class CRT { /*! Sets a function that will map from whatever data the machine provided to a composite signal. @param shader A GLSL fragment including a function with the signature - `float composite_sample(usampler2D texID, vec2 coordinate, vec2 iCoordinate, float phase, float amplitude)` + `float composite_sample(usampler2D texID, vec2 coordinate, float phase, float amplitude)` that evaluates to the composite signal level as a function of a source buffer, sampling location, colour carrier phase and amplitude. */ @@ -290,22 +290,6 @@ class CRT { }); } - /*! - Sets a multiplier applied to iCoordinate values prior to their passing to the various sampling functions. - This multiplier is applied outside of the interpolation loop, making for a more precise interpolation - than if it were applied within the sampling function. - - Idiomatically, this is likely to be the number of output pixels packed into each input sample where - packing is in use. - - The default value is 1.0. - */ - inline void set_integer_coordinate_multiplier(float multiplier) { - enqueue_openGL_function([=] { - openGL_output_builder_.set_integer_coordinate_multiplier(multiplier); - }); - } - enum CompositeSourceType { /// The composite function provides continuous output. Continuous, @@ -362,10 +346,6 @@ class CRT { }); } - inline void set_bookender(std::unique_ptr bookender) { - openGL_output_builder_.texture_builder.set_bookender(std::move(bookender)); - } - inline void set_video_signal(VideoSignal video_signal) { enqueue_openGL_function([video_signal, this] { openGL_output_builder_.set_video_signal(video_signal); diff --git a/Outputs/CRT/Internals/CRTOpenGL.cpp b/Outputs/CRT/Internals/CRTOpenGL.cpp index 2342ccb99..d4739b544 100644 --- a/Outputs/CRT/Internals/CRTOpenGL.cpp +++ b/Outputs/CRT/Internals/CRTOpenGL.cpp @@ -524,12 +524,4 @@ void OpenGLOutputBuilder::set_timing_uniforms() { if(rgb_input_shader_program_) { rgb_input_shader_program_->set_width_scalers(1.0f, 1.0f); } - set_integer_coordinate_multiplier(integer_coordinate_multiplier_); -} - -void OpenGLOutputBuilder::set_integer_coordinate_multiplier(float multiplier) { - integer_coordinate_multiplier_ = multiplier; - if(composite_input_shader_program_) composite_input_shader_program_->set_integer_coordinate_multiplier(multiplier); - if(svideo_input_shader_program_) svideo_input_shader_program_->set_integer_coordinate_multiplier(multiplier); - if(rgb_input_shader_program_) rgb_input_shader_program_->set_integer_coordinate_multiplier(multiplier); } diff --git a/Outputs/CRT/Internals/CRTOpenGL.hpp b/Outputs/CRT/Internals/CRTOpenGL.hpp index c50ac4560..5d9359b64 100644 --- a/Outputs/CRT/Internals/CRTOpenGL.hpp +++ b/Outputs/CRT/Internals/CRTOpenGL.hpp @@ -105,8 +105,6 @@ class OpenGLOutputBuilder { float get_composite_output_width() const; void set_output_shader_width(); - float integer_coordinate_multiplier_ = 1.0f; - // Maintain a couple of rectangles for masking off the extreme edge of the display; // this is a bit of a cheat: there's some tolerance in when a sync pulse will be // generated. So it might be slightly later than expected. Which might cause a scan @@ -174,7 +172,6 @@ class OpenGLOutputBuilder { void set_rgb_sampling_function(const std::string &); void set_video_signal(VideoSignal); void 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); - void set_integer_coordinate_multiplier(float multiplier); }; } diff --git a/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp b/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp index ab886f269..2442e671e 100644 --- a/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp +++ b/Outputs/CRT/Internals/Shaders/IntermediateShader.cpp @@ -46,11 +46,9 @@ std::unique_ptr IntermediateShader::make_shader(const std::s "uniform float inputVerticalOffset;" "uniform float outputVerticalOffset;" "uniform float textureHeightDivisor;" - "uniform float iCoordinateMultiplier;" "out vec3 phaseAndAmplitudeVarying;" "out vec2 inputPositionsVarying[11];" - "out vec2 iInputPositionVarying;" "out vec2 delayLinePositionVarying;" "void main(void)" @@ -75,9 +73,8 @@ std::unique_ptr IntermediateShader::make_shader(const std::s "vec2 extendedInputPosition = " << (input_is_inputPosition ? "inputPosition" : "outputPosition") << " + extensionVector;" "vec2 extendedOutputPosition = outputPosition + extensionVector;" - // keep iInputPositionVarying in whole source pixels, scale mappedInputPosition to the ordinary normalised range + // scale mappedInputPosition to the ordinary normalised range "vec2 textureSize = vec2(textureSize(texID, 0));" - "iInputPositionVarying = extendedInputPosition * iCoordinateMultiplier;" "vec2 mappedInputPosition = extendedInputPosition / textureSize;" // setup input positions spaced as per the supplied offsets; these are for filtering where required @@ -120,7 +117,6 @@ std::unique_ptr IntermediateShader::make_composite_source_sh "#version 150\n" "in vec2 inputPositionsVarying[11];" - "in vec2 iInputPositionVarying;" "in vec3 phaseAndAmplitudeVarying;" "out vec4 fragColour;" @@ -132,18 +128,18 @@ std::unique_ptr IntermediateShader::make_composite_source_sh if(!svideo_shader.empty()) { fragment_shader << svideo_shader << - "float composite_sample(usampler2D texID, vec2 coordinate, vec2 iCoordinate, float phase, float amplitude)" + "float composite_sample(usampler2D texID, vec2 coordinate, float phase, float amplitude)" "{" - "vec2 svideoColour = svideo_sample(texID, coordinate, iCoordinate, phase, amplitude);" + "vec2 svideoColour = svideo_sample(texID, coordinate, phase, amplitude);" "return mix(svideoColour.x, svideoColour.y, abs(amplitude));" "}"; } else { fragment_shader << rgb_shader << "uniform mat3 rgbToLumaChroma;" - "float composite_sample(usampler2D texID, vec2 coordinate, vec2 iCoordinate, float phase, float amplitude)" + "float composite_sample(usampler2D texID, vec2 coordinate, float phase, float amplitude)" "{" - "vec3 rgbColour = clamp(rgb_sample(texID, coordinate, iCoordinate), vec3(0.0), vec3(1.0));" + "vec3 rgbColour = clamp(rgb_sample(texID, coordinate), vec3(0.0), vec3(1.0));" "vec3 lumaChromaColour = rgbToLumaChroma * rgbColour;" "vec2 quadrature = vec2(cos(phase), sin(phase)) * vec2(abs(amplitude), amplitude);" "return dot(lumaChromaColour, vec3(1.0 - abs(amplitude), quadrature));" @@ -154,7 +150,7 @@ std::unique_ptr IntermediateShader::make_composite_source_sh fragment_shader << "void main(void)" "{" - "fragColour = vec4(composite_sample(texID, inputPositionsVarying[5], iInputPositionVarying, phaseAndAmplitudeVarying.x, phaseAndAmplitudeVarying.y));" + "fragColour = vec4(composite_sample(texID, inputPositionsVarying[5], phaseAndAmplitudeVarying.x, phaseAndAmplitudeVarying.y));" "}"; return make_shader(fragment_shader.str(), true, true); @@ -166,7 +162,6 @@ std::unique_ptr IntermediateShader::make_svideo_source_shade "#version 150\n" "in vec2 inputPositionsVarying[11];" - "in vec2 iInputPositionVarying;" "in vec3 phaseAndAmplitudeVarying;" "out vec3 fragColour;" @@ -178,9 +173,9 @@ std::unique_ptr IntermediateShader::make_svideo_source_shade fragment_shader << rgb_shader << "uniform mat3 rgbToLumaChroma;" - "vec2 svideo_sample(usampler2D texID, vec2 coordinate, vec2 iCoordinate, float phase, float amplitude)" + "vec2 svideo_sample(usampler2D texID, vec2 coordinate, float phase, float amplitude)" "{" - "vec3 rgbColour = clamp(rgb_sample(texID, coordinate, iCoordinate), vec3(0.0), vec3(1.0));" + "vec3 rgbColour = clamp(rgb_sample(texID, coordinate), vec3(0.0), vec3(1.0));" "vec3 lumaChromaColour = rgbToLumaChroma * rgbColour;" "vec2 quadrature = vec2(cos(phase), sin(phase)) * vec2(1.0, sign(amplitude));" "return vec2(lumaChromaColour.x, 0.5 + dot(quadrature, lumaChromaColour.yz) * 0.5);" @@ -190,7 +185,7 @@ std::unique_ptr IntermediateShader::make_svideo_source_shade fragment_shader << "void main(void)" "{" - "vec2 sample = svideo_sample(texID, inputPositionsVarying[5], iInputPositionVarying, phaseAndAmplitudeVarying.x, phaseAndAmplitudeVarying.y);" + "vec2 sample = svideo_sample(texID, inputPositionsVarying[5], phaseAndAmplitudeVarying.x, phaseAndAmplitudeVarying.y);" "vec2 quadrature = vec2(cos(phaseAndAmplitudeVarying.x), sin(phaseAndAmplitudeVarying.x)) * vec2(1.0, sign(phaseAndAmplitudeVarying.y)) * 0.5 * phaseAndAmplitudeVarying.z;" "fragColour = vec3(sample.x, vec2(0.5) + (sample.y * quadrature));" "}"; @@ -204,7 +199,6 @@ std::unique_ptr IntermediateShader::make_rgb_source_shader(c "#version 150\n" "in vec2 inputPositionsVarying[11];" - "in vec2 iInputPositionVarying;" "in vec3 phaseAndAmplitudeVarying;" "out vec3 fragColour;" @@ -215,7 +209,7 @@ std::unique_ptr IntermediateShader::make_rgb_source_shader(c "void main(void)" "{" - "fragColour = rgb_sample(texID, inputPositionsVarying[5], iInputPositionVarying);" + "fragColour = rgb_sample(texID, inputPositionsVarying[5]);" "}"; return make_shader(fragment_shader.str(), true, true); @@ -439,7 +433,3 @@ void IntermediateShader::set_is_double_height(bool is_double_height, float input set_uniform("inputVerticalOffset", input_offset); set_uniform("outputVerticalOffset", output_offset); } - -void IntermediateShader::set_integer_coordinate_multiplier(float multiplier) { - set_uniform("iCoordinateMultiplier", multiplier); -} diff --git a/Outputs/CRT/Internals/Shaders/IntermediateShader.hpp b/Outputs/CRT/Internals/Shaders/IntermediateShader.hpp index ff8316893..d8c5e9699 100644 --- a/Outputs/CRT/Internals/Shaders/IntermediateShader.hpp +++ b/Outputs/CRT/Internals/Shaders/IntermediateShader.hpp @@ -135,11 +135,6 @@ public: */ void set_is_double_height(bool is_double_height, float input_offset = 0.0f, float output_offset = 0.0f); - /*! - Sets the multiplier applied in the vertex shader to iCoordinates. - */ - void set_integer_coordinate_multiplier(float); - private: static std::unique_ptr make_shader(const std::string &fragment_shader, bool use_usampler, bool input_is_inputPosition); }; diff --git a/Outputs/CRT/Internals/TextureBuilder.cpp b/Outputs/CRT/Internals/TextureBuilder.cpp index 526332f32..102653771 100644 --- a/Outputs/CRT/Internals/TextureBuilder.cpp +++ b/Outputs/CRT/Internals/TextureBuilder.cpp @@ -36,19 +36,6 @@ const GLenum formatForDepth(std::size_t depth) { } } -struct DefaultBookender: public TextureBuilder::Bookender { - public: - DefaultBookender(std::size_t bytes_per_pixel) : bytes_per_pixel_(bytes_per_pixel) {} - - void add_bookends(uint8_t *const left_value, uint8_t *const right_value, uint8_t *left_bookend, uint8_t *right_bookend) { - std::memcpy(left_bookend, left_value, bytes_per_pixel_); - std::memcpy(right_bookend, right_value, bytes_per_pixel_); - } - - private: - std::size_t bytes_per_pixel_; -}; - } TextureBuilder::TextureBuilder(std::size_t bytes_per_pixel, GLenum texture_unit) : @@ -58,8 +45,6 @@ TextureBuilder::TextureBuilder(std::size_t bytes_per_pixel, GLenum texture_unit) bind(); glTexImage2D(GL_TEXTURE_2D, 0, internalFormatForDepth(bytes_per_pixel), InputBufferBuilderWidth, InputBufferBuilderHeight, 0, formatForDepth(bytes_per_pixel), GL_UNSIGNED_BYTE, nullptr); - - set_bookender(nullptr); } TextureBuilder::~TextureBuilder() { @@ -119,17 +104,9 @@ void TextureBuilder::reduce_previous_allocation_to(std::size_t actual_length) { // Bookend the allocation with duplicates of the first and last pixel, to protect // against rounding errors when this run is drawn. - // TODO: allow somebody else to specify the rule for generating a left-padding value and - // a right-padding value. uint8_t *start_pointer = pointer_to_location(write_area_.x, write_area_.y) - bytes_per_pixel_; - bookender_->add_bookends(&start_pointer[bytes_per_pixel_], &start_pointer[actual_length * bytes_per_pixel_], start_pointer, &start_pointer[(actual_length + 1) * bytes_per_pixel_]); -} - -void TextureBuilder::set_bookender(std::unique_ptr bookender) { - bookender_ = std::move(bookender); - if(!bookender_) { - bookender_.reset(new DefaultBookender(bytes_per_pixel_)); - } + std::memcpy(start_pointer, &start_pointer[bytes_per_pixel_], bytes_per_pixel_); + std::memcpy(&start_pointer[(actual_length + 1) * bytes_per_pixel_], &start_pointer[actual_length * bytes_per_pixel_], bytes_per_pixel_); } bool TextureBuilder::retain_latest() { diff --git a/Outputs/CRT/Internals/TextureBuilder.hpp b/Outputs/CRT/Internals/TextureBuilder.hpp index 44142100b..9770fd03f 100644 --- a/Outputs/CRT/Internals/TextureBuilder.hpp +++ b/Outputs/CRT/Internals/TextureBuilder.hpp @@ -98,22 +98,6 @@ class TextureBuilder { /// allocated, indicating their final resting locations and their lengths. void flush(const std::function &write_areas, std::size_t count)> &); - /// A Bookender helps to paper over precision errors when rendering; its job is to provide single-sample - /// extensions that duplicate the left and right edges of a written area. By default the texture builder will - /// simply copy the appropriate number of bytes per pixel, but if the client is using a packed pixel format - /// then that may be incorrect, e.g. if each sample is a byte but contains two pixels, each in a single nibble, - /// then the correct duplication might be a byte composed of copies of the two top nibbles as the left bookend, - /// and one composed of copies of the two bottom nibbles on the right. - struct Bookender { - /// Writes to left_bookend the sample that should appear as a continuation before the left_value; - /// writes to right_bookend the sample that should appear as a continuation after right_value. - virtual void add_bookends(uint8_t *const left_value, uint8_t *const right_value, uint8_t *left_bookend, uint8_t *right_bookend) = 0; - }; - - /// Sets the current bookender. The bookender be called synchronously within the builder-writing thread. - /// Supply nullptr to engage the default bookender. - void set_bookender(std::unique_ptr bookender); - /// Binds this texture to the unit supplied at instantiation. void bind(); @@ -140,8 +124,6 @@ class TextureBuilder { // Caveat: reset to the origin upon a submit. So used in comparison by flush to // determine whether the current batch of write areas needs to be relocated. uint16_t write_areas_start_x_ = 0, write_areas_start_y_ = 0; - - std::unique_ptr bookender_; }; }