1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-26 08:49:37 +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)
{
_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);
}
}
}

View File

@ -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<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));
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

View File

@ -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<Outputs::Flywheel> _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)

View File

@ -7,6 +7,7 @@
#include "CRT.hpp"
#include <stdlib.h>
#include <math.h>
#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);