1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-30 23:29:08 +00:00

Made an attempt to fix tape output interrupts; offloaded raster width and placing conversion to the GPU.

This commit is contained in:
Thomas Harte 2016-02-27 20:37:41 -05:00
parent db18c85423
commit 1c6de7692d
4 changed files with 27 additions and 50 deletions

View File

@ -770,7 +770,8 @@ inline void Tape::set_counter(uint8_t value)
inline void Tape::set_data_register(uint8_t value) inline void Tape::set_data_register(uint8_t value)
{ {
_data_register = (uint16_t)((value << 2) | 1); _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() 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()) if(_output_pulse_stepper->step())
{ {
_output_bits_remaining--; _output_bits_remaining--;
_bits_since_start--;
if(!_output_bits_remaining) if(!_output_bits_remaining)
{ {
_output_bits_remaining = 9; _output_bits_remaining = 9;
@ -840,6 +842,7 @@ inline void Tape::run_for_cycles(unsigned int number_of_cycles)
evaluate_interrupts(); evaluate_interrupts();
_data_register = (_data_register >> 1) | 0x200; _data_register = (_data_register >> 1) | 0x200;
printf("Shifted — %03x\n", _data_register);
} }
} }
} }

View File

@ -13,12 +13,6 @@
using namespace Outputs; 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) 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; _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 // generate timing values implied by the given arbuments
_sync_capacitor_charge_threshold = ((syncCapacityLineChargeThreshold * _cycles_per_line) * 50) >> 7; _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 // create the two flywheels
unsigned int horizontal_retrace_time = scanlinesVerticalRetraceTime * _cycles_per_line;
_horizontal_flywheel = std::unique_ptr<Outputs::Flywheel>(new Outputs::Flywheel(_cycles_per_line, (millisecondsHorizontalRetraceTime * _cycles_per_line) >> 6)); _horizontal_flywheel = std::unique_ptr<Outputs::Flywheel>(new Outputs::Flywheel(_cycles_per_line, (millisecondsHorizontalRetraceTime * _cycles_per_line) >> 6));
_vertical_flywheel = std::unique_ptr<Outputs::Flywheel>(new Outputs::Flywheel(_cycles_per_line * height_of_display, scanlinesVerticalRetraceTime * _cycles_per_line)); _vertical_flywheel = std::unique_ptr<Outputs::Flywheel>(new Outputs::Flywheel(_cycles_per_line * height_of_display, scanlinesVerticalRetraceTime * _cycles_per_line));
for(int c = 0; c < 4; c++) // 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);
_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);
}
} }
void CRT::set_new_display_type(unsigned int cycles_per_line, DisplayType displayType) void CRT::set_new_display_type(unsigned int cycles_per_line, DisplayType displayType)
@ -98,7 +81,6 @@ CRT::CRT() :
_is_receiving_sync(false), _is_receiving_sync(false),
_output_mutex(new std::mutex), _output_mutex(new std::mutex),
_visible_area(Rect(0, 0, 1, 1)), _visible_area(Rect(0, 0, 1, 1)),
_rasterPosition({.x = 0, .y = 0}),
_sync_period(0) _sync_period(0)
{ {
construct_openGL(); construct_openGL();
@ -166,7 +148,6 @@ void CRT::advance_cycles(unsigned int number_of_cycles, unsigned int source_divi
vsync_requested = false; 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; 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_x(v) (*(uint16_t *)&next_run[kCRTSizeOfVertex*v + kCRTVertexOffsetOfPosition + 0])
#define position_y(v) (*(uint16_t *)&next_run[kCRTSizeOfVertex*v + kCRTVertexOffsetOfPosition + 2]) #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 lateral(v) next_run[kCRTSizeOfVertex*v + kCRTVertexOffsetOfLateral]
#define timestamp(v) (*(uint32_t *)&next_run[kCRTSizeOfVertex*v + kCRTVertexOffsetOfTimestamp]) #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) 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 // 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_x(0) = position_x(1) = position_x(4) = (uint16_t)_horizontal_flywheel->get_current_output_position();
position_y(0) = position_y(4) = InternalToUInt16(kCRTFixedPointOffset + y_position + _beamWidth[lengthMask].y); position_y(0) = position_y(1) = position_y(4) = (uint16_t)(_vertical_flywheel->get_current_output_position() / _vertical_flywheel_output_divider);
position_x(1) = InternalToUInt16(kCRTFixedPointOffset + x_position - _beamWidth[lengthMask].x);
position_y(1) = InternalToUInt16(kCRTFixedPointOffset + y_position - _beamWidth[lengthMask].y);
timestamp(0) = timestamp(1) = timestamp(4) = _run_builders[_run_write_pointer]->duration; timestamp(0) = timestamp(1) = timestamp(4) = _run_builders[_run_write_pointer]->duration;
tex_x(0) = tex_x(1) = tex_x(4) = tex_x; tex_x(0) = tex_x(1) = tex_x(4) = tex_x;
// these things are constants across the line so just throw them out now // 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) if(next_run)
{ {
unsigned int x_position = CounterToInternal(_horizontal_flywheel);
unsigned int y_position = CounterToInternal(_vertical_flywheel);
// store the final raster position // store the final raster position
position_x(2) = position_x(3) = InternalToUInt16(kCRTFixedPointOffset + x_position - _beamWidth[lengthMask].x); position_x(2) = position_x(3) = position_x(5) = (uint16_t)_horizontal_flywheel->get_current_output_position();
position_y(2) = position_y(3) = InternalToUInt16(kCRTFixedPointOffset + y_position - _beamWidth[lengthMask].y); position_y(2) = position_y(3) = position_y(5) = (uint16_t)(_vertical_flywheel->get_current_output_position() / _vertical_flywheel_output_divider);
position_x(5) = InternalToUInt16(kCRTFixedPointOffset + x_position + _beamWidth[lengthMask].x);
position_y(5) = InternalToUInt16(kCRTFixedPointOffset + y_position + _beamWidth[lengthMask].y);
timestamp(2) = timestamp(3) = timestamp(5) = _run_builders[_run_write_pointer]->duration; timestamp(2) = timestamp(3) = timestamp(5) = _run_builders[_run_write_pointer]->duration;
// if this is a data run then advance the buffer pointer // if this is a data run then advance the buffer pointer

View File

@ -252,13 +252,9 @@ class CRT {
// The user-supplied visible area // The user-supplied visible area
Rect _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 // the two flywheels regulating scanning
std::unique_ptr<Outputs::Flywheel> _horizontal_flywheel, _vertical_flywheel; std::unique_ptr<Outputs::Flywheel> _horizontal_flywheel, _vertical_flywheel;
uint16_t _vertical_flywheel_output_divider;
// elements of sync separation // 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) bool _is_receiving_sync; // true if the CRT is currently receiving sync (i.e. this is for edge triggering of horizontal sync)

View File

@ -7,6 +7,7 @@
#include "CRT.hpp" #include "CRT.hpp"
#include <stdlib.h> #include <stdlib.h>
#include <math.h>
#include "OpenGL.hpp" #include "OpenGL.hpp"
#include "TextureTarget.hpp" #include "TextureTarget.hpp"
@ -255,6 +256,8 @@ char *CRT::get_vertex_shader()
"uniform vec2 textureSize;" "uniform vec2 textureSize;"
"uniform float timestampBase;" "uniform float timestampBase;"
"uniform float ticksPerFrame;" "uniform float ticksPerFrame;"
"uniform vec2 positionConversion;"
"uniform vec2 scanNormal;"
"const float shadowMaskMultiple = 600;" "const float shadowMaskMultiple = 600;"
@ -270,7 +273,8 @@ char *CRT::get_vertex_shader()
"float age = (timestampBase - timestamp) / ticksPerFrame;" "float age = (timestampBase - timestamp) / ticksPerFrame;"
"alpha = min(10.0 * exp(-age * 2.0), 1.0);" "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);" "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 shadowMaskTexIDUniform = _openGL_state->shaderProgram->get_uniform_location("shadowMaskTexID");
GLint textureSizeUniform = _openGL_state->shaderProgram->get_uniform_location("textureSize"); GLint textureSizeUniform = _openGL_state->shaderProgram->get_uniform_location("textureSize");
GLint ticksPerFrameUniform = _openGL_state->shaderProgram->get_uniform_location("ticksPerFrame"); 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(texIDUniform, 0);
glUniform1i(shadowMaskTexIDUniform, 1); glUniform1i(shadowMaskTexIDUniform, 1);
glUniform2f(textureSizeUniform, CRTInputBufferBuilderWidth, CRTInputBufferBuilderHeight); glUniform2f(textureSizeUniform, CRTInputBufferBuilderWidth, CRTInputBufferBuilderHeight);
glUniform1f(ticksPerFrameUniform, (GLfloat)(_cycles_per_line * _height_of_display)); 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() void CRT::prepare_vertex_array()
@ -376,7 +389,7 @@ void CRT::prepare_vertex_array()
glEnableVertexAttribArray((GLuint)_openGL_state->timestampAttribute); glEnableVertexAttribArray((GLuint)_openGL_state->timestampAttribute);
const GLsizei vertexStride = kCRTSizeOfVertex; 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->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->timestampAttribute, 4, GL_UNSIGNED_INT, GL_FALSE, vertexStride, (void *)kCRTVertexOffsetOfTimestamp);
glVertexAttribPointer((GLuint)_openGL_state->lateralAttribute, 1, GL_UNSIGNED_BYTE, GL_FALSE, vertexStride, (void *)kCRTVertexOffsetOfLateral); glVertexAttribPointer((GLuint)_openGL_state->lateralAttribute, 1, GL_UNSIGNED_BYTE, GL_FALSE, vertexStride, (void *)kCRTVertexOffsetOfLateral);