From 1c6de7692d6d41b48c46935ee9dc949d954e679d Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 27 Feb 2016 20:37:41 -0500 Subject: [PATCH] Made an attempt to fix tape output interrupts; offloaded raster width and placing conversion to the GPU. --- Machines/Electron/Electron.cpp | 5 +++- Outputs/CRT/CRT.cpp | 49 +++++----------------------------- Outputs/CRT/CRT.hpp | 6 +---- Outputs/CRT/CRTOpenGL.cpp | 17 ++++++++++-- 4 files changed, 27 insertions(+), 50 deletions(-) diff --git a/Machines/Electron/Electron.cpp b/Machines/Electron/Electron.cpp index 3f36eed91..1124f4528 100644 --- a/Machines/Electron/Electron.cpp +++ b/Machines/Electron/Electron.cpp @@ -770,7 +770,8 @@ inline void Tape::set_counter(uint8_t value) inline void Tape::set_data_register(uint8_t value) { _data_register = (uint16_t)((value << 2) | 1); - _output_bits_remaining = 9; + printf("Loaded — %03x\n", _data_register); + _bits_since_start = _output_bits_remaining = 9; } inline uint8_t Tape::get_data_register() @@ -831,6 +832,7 @@ inline void Tape::run_for_cycles(unsigned int number_of_cycles) if(_output_pulse_stepper->step()) { _output_bits_remaining--; + _bits_since_start--; if(!_output_bits_remaining) { _output_bits_remaining = 9; @@ -840,6 +842,7 @@ inline void Tape::run_for_cycles(unsigned int number_of_cycles) evaluate_interrupts(); _data_register = (_data_register >> 1) | 0x200; + printf("Shifted — %03x\n", _data_register); } } } diff --git a/Outputs/CRT/CRT.cpp b/Outputs/CRT/CRT.cpp index 95284e195..cebcee55f 100644 --- a/Outputs/CRT/CRT.cpp +++ b/Outputs/CRT/CRT.cpp @@ -13,12 +13,6 @@ using namespace Outputs; -static const uint32_t kCRTFixedPointRange = 0xf7ffffff; -static const uint32_t kCRTFixedPointOffset = 0x04000000; - -#define kRetraceXMask 0x01 -#define kRetraceYMask 0x02 - void CRT::set_new_timing(unsigned int cycles_per_line, unsigned int height_of_display, ColourSpace colour_space, unsigned int colour_cycle_numerator, unsigned int colour_cycle_denominator) { _colour_space = colour_space; @@ -43,24 +37,13 @@ void CRT::set_new_timing(unsigned int cycles_per_line, unsigned int height_of_di // generate timing values implied by the given arbuments _sync_capacitor_charge_threshold = ((syncCapacityLineChargeThreshold * _cycles_per_line) * 50) >> 7; - const unsigned int vertical_retrace_time = scanlinesVerticalRetraceTime * _cycles_per_line; - const float halfLineWidth = (float)_height_of_display * 1.94f; - // creat the two flywheels - unsigned int horizontal_retrace_time = scanlinesVerticalRetraceTime * _cycles_per_line; + // create the two flywheels _horizontal_flywheel = std::unique_ptr(new Outputs::Flywheel(_cycles_per_line, (millisecondsHorizontalRetraceTime * _cycles_per_line) >> 6)); _vertical_flywheel = std::unique_ptr(new Outputs::Flywheel(_cycles_per_line * height_of_display, scanlinesVerticalRetraceTime * _cycles_per_line)); - for(int c = 0; c < 4; c++) - { - _scanSpeed[c].x = (c&kRetraceXMask) ? -(kCRTFixedPointRange / horizontal_retrace_time) : (kCRTFixedPointRange / _cycles_per_line); - _scanSpeed[c].y = (c&kRetraceYMask) ? -(kCRTFixedPointRange / vertical_retrace_time) : (kCRTFixedPointRange / (_height_of_display * _cycles_per_line)); - - // width should be 1.0 / _height_of_display, rotated to match the direction - float angle = atan2f(_scanSpeed[c].y, _scanSpeed[c].x); - _beamWidth[c].x = (uint32_t)((sinf(angle) / halfLineWidth) * kCRTFixedPointRange); - _beamWidth[c].y = (uint32_t)((cosf(angle) / halfLineWidth) * kCRTFixedPointRange); - } + // figure out the divisor necessary to get the horizontal flywheel into a 16-bit range + _vertical_flywheel_output_divider = (uint16_t)ceilf(_vertical_flywheel->get_scan_period() / 65536.0f); } void CRT::set_new_display_type(unsigned int cycles_per_line, DisplayType displayType) @@ -98,7 +81,6 @@ CRT::CRT() : _is_receiving_sync(false), _output_mutex(new std::mutex), _visible_area(Rect(0, 0, 1, 1)), - _rasterPosition({.x = 0, .y = 0}), _sync_period(0) { construct_openGL(); @@ -166,7 +148,6 @@ void CRT::advance_cycles(unsigned int number_of_cycles, unsigned int source_divi vsync_requested = false; uint8_t *next_run = ((is_output_run && next_run_length) && !_horizontal_flywheel->is_in_retrace() && !_vertical_flywheel->is_in_retrace()) ? _run_builders[_run_write_pointer]->get_next_run() : nullptr; - int lengthMask = (_horizontal_flywheel->is_in_retrace() ? kRetraceXMask : 0) | (_vertical_flywheel->is_in_retrace() ? kRetraceYMask : 0); #define position_x(v) (*(uint16_t *)&next_run[kCRTSizeOfVertex*v + kCRTVertexOffsetOfPosition + 0]) #define position_y(v) (*(uint16_t *)&next_run[kCRTSizeOfVertex*v + kCRTVertexOffsetOfPosition + 2]) @@ -175,22 +156,12 @@ void CRT::advance_cycles(unsigned int number_of_cycles, unsigned int source_divi #define lateral(v) next_run[kCRTSizeOfVertex*v + kCRTVertexOffsetOfLateral] #define timestamp(v) (*(uint32_t *)&next_run[kCRTSizeOfVertex*v + kCRTVertexOffsetOfTimestamp]) -#define InternalToUInt16(v) ((v) + 32768) >> 16 -#define CounterToInternal(c) (unsigned int)(((uint64_t)c->get_current_output_position() * kCRTFixedPointRange) / c->get_scan_period()) - if(next_run) { - unsigned int x_position = CounterToInternal(_horizontal_flywheel); - unsigned int y_position = CounterToInternal(_vertical_flywheel); - // set the type, initial raster position and type of this run - position_x(0) = position_x(4) = InternalToUInt16(kCRTFixedPointOffset + x_position + _beamWidth[lengthMask].x); - position_y(0) = position_y(4) = InternalToUInt16(kCRTFixedPointOffset + y_position + _beamWidth[lengthMask].y); - position_x(1) = InternalToUInt16(kCRTFixedPointOffset + x_position - _beamWidth[lengthMask].x); - position_y(1) = InternalToUInt16(kCRTFixedPointOffset + y_position - _beamWidth[lengthMask].y); - + position_x(0) = position_x(1) = position_x(4) = (uint16_t)_horizontal_flywheel->get_current_output_position(); + position_y(0) = position_y(1) = position_y(4) = (uint16_t)(_vertical_flywheel->get_current_output_position() / _vertical_flywheel_output_divider); timestamp(0) = timestamp(1) = timestamp(4) = _run_builders[_run_write_pointer]->duration; - tex_x(0) = tex_x(1) = tex_x(4) = tex_x; // these things are constants across the line so just throw them out now @@ -216,15 +187,9 @@ void CRT::advance_cycles(unsigned int number_of_cycles, unsigned int source_divi if(next_run) { - unsigned int x_position = CounterToInternal(_horizontal_flywheel); - unsigned int y_position = CounterToInternal(_vertical_flywheel); - // store the final raster position - position_x(2) = position_x(3) = InternalToUInt16(kCRTFixedPointOffset + x_position - _beamWidth[lengthMask].x); - position_y(2) = position_y(3) = InternalToUInt16(kCRTFixedPointOffset + y_position - _beamWidth[lengthMask].y); - position_x(5) = InternalToUInt16(kCRTFixedPointOffset + x_position + _beamWidth[lengthMask].x); - position_y(5) = InternalToUInt16(kCRTFixedPointOffset + y_position + _beamWidth[lengthMask].y); - + position_x(2) = position_x(3) = position_x(5) = (uint16_t)_horizontal_flywheel->get_current_output_position(); + position_y(2) = position_y(3) = position_y(5) = (uint16_t)(_vertical_flywheel->get_current_output_position() / _vertical_flywheel_output_divider); timestamp(2) = timestamp(3) = timestamp(5) = _run_builders[_run_write_pointer]->duration; // if this is a data run then advance the buffer pointer diff --git a/Outputs/CRT/CRT.hpp b/Outputs/CRT/CRT.hpp index 121be4eb9..eb34dd6e0 100644 --- a/Outputs/CRT/CRT.hpp +++ b/Outputs/CRT/CRT.hpp @@ -252,13 +252,9 @@ class CRT { // The user-supplied visible area Rect _visible_area; - // the current scanning position (TODO: can I eliminate this in favour of just using the flywheels?) - struct Vector { - uint32_t x, y; - } _rasterPosition, _scanSpeed[4], _beamWidth[4]; - // the two flywheels regulating scanning std::unique_ptr _horizontal_flywheel, _vertical_flywheel; + uint16_t _vertical_flywheel_output_divider; // elements of sync separation bool _is_receiving_sync; // true if the CRT is currently receiving sync (i.e. this is for edge triggering of horizontal sync) diff --git a/Outputs/CRT/CRTOpenGL.cpp b/Outputs/CRT/CRTOpenGL.cpp index da53f5b15..bbfee5601 100644 --- a/Outputs/CRT/CRTOpenGL.cpp +++ b/Outputs/CRT/CRTOpenGL.cpp @@ -7,6 +7,7 @@ #include "CRT.hpp" #include +#include #include "OpenGL.hpp" #include "TextureTarget.hpp" @@ -255,6 +256,8 @@ char *CRT::get_vertex_shader() "uniform vec2 textureSize;" "uniform float timestampBase;" "uniform float ticksPerFrame;" + "uniform vec2 positionConversion;" + "uniform vec2 scanNormal;" "const float shadowMaskMultiple = 600;" @@ -270,7 +273,8 @@ char *CRT::get_vertex_shader() "float age = (timestampBase - timestamp) / ticksPerFrame;" "alpha = min(10.0 * exp(-age * 2.0), 1.0);" - "vec2 mappedPosition = (position - boundsOrigin) / boundsSize;" + "vec2 floatingPosition = (position / positionConversion) + lateral*scanNormal;" + "vec2 mappedPosition = (floatingPosition - boundsOrigin) / boundsSize;" "gl_Position = vec4(mappedPosition.x * 2.0 - 1.0, 1.0 - mappedPosition.y * 2.0, 0.0, 1.0);" "}"); } @@ -361,11 +365,20 @@ void CRT::prepare_shader() GLint shadowMaskTexIDUniform = _openGL_state->shaderProgram->get_uniform_location("shadowMaskTexID"); GLint textureSizeUniform = _openGL_state->shaderProgram->get_uniform_location("textureSize"); GLint ticksPerFrameUniform = _openGL_state->shaderProgram->get_uniform_location("ticksPerFrame"); + GLint scanNormalUniform = _openGL_state->shaderProgram->get_uniform_location("scanNormal"); + GLint positionConversionUniform = _openGL_state->shaderProgram->get_uniform_location("positionConversion"); glUniform1i(texIDUniform, 0); glUniform1i(shadowMaskTexIDUniform, 1); glUniform2f(textureSizeUniform, CRTInputBufferBuilderWidth, CRTInputBufferBuilderHeight); glUniform1f(ticksPerFrameUniform, (GLfloat)(_cycles_per_line * _height_of_display)); + glUniform2f(positionConversionUniform, _horizontal_flywheel->get_scan_period(), _vertical_flywheel->get_scan_period() / (unsigned int)_vertical_flywheel_output_divider); + + float scan_angle = atan2f(1.0f / (float)_height_of_display, 1.0f); + float scan_normal[] = { sinf(scan_angle), cosf(scan_angle)}; + scan_normal[0] /= (float)_height_of_display; + scan_normal[1] /= (float)_height_of_display; + glUniform2f(scanNormalUniform, scan_normal[0], scan_normal[1]); } void CRT::prepare_vertex_array() @@ -376,7 +389,7 @@ void CRT::prepare_vertex_array() glEnableVertexAttribArray((GLuint)_openGL_state->timestampAttribute); const GLsizei vertexStride = kCRTSizeOfVertex; - glVertexAttribPointer((GLuint)_openGL_state->positionAttribute, 2, GL_UNSIGNED_SHORT, GL_TRUE, vertexStride, (void *)kCRTVertexOffsetOfPosition); + glVertexAttribPointer((GLuint)_openGL_state->positionAttribute, 2, GL_UNSIGNED_SHORT, GL_FALSE, vertexStride, (void *)kCRTVertexOffsetOfPosition); glVertexAttribPointer((GLuint)_openGL_state->textureCoordinatesAttribute, 2, GL_UNSIGNED_SHORT, GL_FALSE, vertexStride, (void *)kCRTVertexOffsetOfTexCoord); glVertexAttribPointer((GLuint)_openGL_state->timestampAttribute, 4, GL_UNSIGNED_INT, GL_FALSE, vertexStride, (void *)kCRTVertexOffsetOfTimestamp); glVertexAttribPointer((GLuint)_openGL_state->lateralAttribute, 1, GL_UNSIGNED_BYTE, GL_FALSE, vertexStride, (void *)kCRTVertexOffsetOfLateral);