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:
parent
db18c85423
commit
1c6de7692d
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user