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:
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)
|
||||
{
|
||||
_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user