1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-12-25 03:32:01 +00:00

With the provision of an extra hint to the CRT and, finally, the realisation about why my scans weren't exactly joining up, improved output precision.

This commit is contained in:
Thomas Harte 2016-02-27 22:39:01 -05:00
parent 1c6de7692d
commit 7839d93344
6 changed files with 31 additions and 14 deletions

View File

@ -24,7 +24,7 @@ Machine::Machine() :
_piaDataValue{0xff, 0xff}, _piaDataValue{0xff, 0xff},
_tiaInputValue{0xff, 0xff} _tiaInputValue{0xff, 0xff}
{ {
_crt = new Outputs::CRT(228, Outputs::CRT::DisplayType::NTSC60, 1, 2); _crt = new Outputs::CRT(228, 1, Outputs::CRT::DisplayType::NTSC60, 1, 2);
_crt->set_composite_sampling_function( _crt->set_composite_sampling_function(
"float sample(vec2 coordinate, float phase)\n" "float sample(vec2 coordinate, float phase)\n"
"{\n" "{\n"

View File

@ -32,7 +32,7 @@ Machine::Machine() :
_audioOutputPositionError(0), _audioOutputPositionError(0),
_currentOutputLine(0), _currentOutputLine(0),
_is_odd_field(false), _is_odd_field(false),
_crt(std::unique_ptr<Outputs::CRT>(new Outputs::CRT(crt_cycles_per_line, Outputs::CRT::DisplayType::PAL50, 1, 1))) _crt(std::unique_ptr<Outputs::CRT>(new Outputs::CRT(crt_cycles_per_line, 8, Outputs::CRT::DisplayType::PAL50, 1, 1)))
{ {
_crt->set_rgb_sampling_function( _crt->set_rgb_sampling_function(
"vec3 rgb_sample(vec2 coordinate)" "vec3 rgb_sample(vec2 coordinate)"

View File

@ -43,7 +43,8 @@ void CRT::set_new_timing(unsigned int cycles_per_line, unsigned int height_of_di
_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));
// figure out the divisor necessary to get the horizontal flywheel into a 16-bit range // 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); unsigned int real_clock_scan_period = (_cycles_per_line * height_of_display) / (_time_multiplier * _common_output_divisor);
_vertical_flywheel_output_divider = (uint16_t)(ceilf(real_clock_scan_period / 65536.0f) * (_time_multiplier * _common_output_divisor));
} }
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)
@ -74,14 +75,15 @@ void CRT::allocate_buffers(unsigned int number, va_list sizes)
va_end(va); va_end(va);
} }
CRT::CRT() : CRT::CRT(unsigned int common_output_divisor) :
_next_scan(0), _next_scan(0),
_run_write_pointer(0), _run_write_pointer(0),
_sync_capacitor_charge_level(0), _sync_capacitor_charge_level(0),
_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)),
_sync_period(0) _sync_period(0),
_common_output_divisor(common_output_divisor)
{ {
construct_openGL(); construct_openGL();
} }
@ -96,7 +98,7 @@ CRT::~CRT()
destruct_openGL(); destruct_openGL();
} }
CRT::CRT(unsigned int cycles_per_line, unsigned int height_of_display, ColourSpace colour_space, unsigned int colour_cycle_numerator, unsigned int colour_cycle_denominator, unsigned int number_of_buffers, ...) : CRT() CRT::CRT(unsigned int cycles_per_line, unsigned int common_output_divisor, unsigned int height_of_display, ColourSpace colour_space, unsigned int colour_cycle_numerator, unsigned int colour_cycle_denominator, unsigned int number_of_buffers, ...) : CRT(common_output_divisor)
{ {
set_new_timing(cycles_per_line, height_of_display, colour_space, colour_cycle_numerator, colour_cycle_denominator); set_new_timing(cycles_per_line, height_of_display, colour_space, colour_cycle_numerator, colour_cycle_denominator);
@ -106,7 +108,7 @@ CRT::CRT(unsigned int cycles_per_line, unsigned int height_of_display, ColourSpa
va_end(buffer_sizes); va_end(buffer_sizes);
} }
CRT::CRT(unsigned int cycles_per_line, DisplayType displayType, unsigned int number_of_buffers, ...) : CRT() CRT::CRT(unsigned int cycles_per_line, unsigned int common_output_divisor, DisplayType displayType, unsigned int number_of_buffers, ...) : CRT(common_output_divisor)
{ {
set_new_display_type(cycles_per_line, displayType); set_new_display_type(cycles_per_line, displayType);

View File

@ -59,6 +59,11 @@ class CRT {
@param cycles_per_line The clock rate at which this CRT will be driven, specified as the number @param cycles_per_line The clock rate at which this CRT will be driven, specified as the number
of cycles expected to take up one whole scanline of the display. of cycles expected to take up one whole scanline of the display.
@param common_output_divisor The greatest a priori common divisor of all cycle counts that will be
supplied to @c output_sync, @c output_data, etc; supply 1 if no greater divisor is known. For many
machines output will run at a fixed multiple of the clock rate; knowing this divisor can improve
internal precision.
@param height_of_dispaly The number of lines that nominally form one field of the display, rounded @param height_of_dispaly The number of lines that nominally form one field of the display, rounded
up to the next whole integer. up to the next whole integer.
@ -79,7 +84,7 @@ class CRT {
@see @c set_rgb_sampling_function , @c set_composite_sampling_function @see @c set_rgb_sampling_function , @c set_composite_sampling_function
*/ */
CRT(unsigned int cycles_per_line, unsigned int height_of_display, ColourSpace colour_space, unsigned int colour_cycle_numerator, unsigned int colour_cycle_denominator, unsigned int number_of_buffers, ...); CRT(unsigned int cycles_per_line, unsigned int common_output_divisor, unsigned int height_of_display, ColourSpace colour_space, unsigned int colour_cycle_numerator, unsigned int colour_cycle_denominator, unsigned int number_of_buffers, ...);
/*! Constructs the CRT with the specified clock rate, with the display height and colour /*! Constructs the CRT with the specified clock rate, with the display height and colour
subcarrier frequency dictated by a standard display type and with the requested number of subcarrier frequency dictated by a standard display type and with the requested number of
@ -88,7 +93,7 @@ class CRT {
Exactly identical to calling the designated constructor with colour subcarrier information Exactly identical to calling the designated constructor with colour subcarrier information
looked up by display type. looked up by display type.
*/ */
CRT(unsigned int cycles_per_line, DisplayType displayType, unsigned int number_of_buffers, ...); CRT(unsigned int cycles_per_line, unsigned int common_output_divisor, DisplayType displayType, unsigned int number_of_buffers, ...);
/*! Resets the CRT with new timing information. The CRT then continues as though the new timing had /*! Resets the CRT with new timing information. The CRT then continues as though the new timing had
been provided at construction. */ been provided at construction. */
@ -232,12 +237,13 @@ class CRT {
#endif #endif
private: private:
CRT(); CRT(unsigned int common_output_divisor);
void allocate_buffers(unsigned int number, va_list sizes); void allocate_buffers(unsigned int number, va_list sizes);
// the incoming clock lengths will be multiplied by something to give at least 1000 // the incoming clock lengths will be multiplied by something to give at least 1000
// sample points per line // sample points per line
unsigned int _time_multiplier; unsigned int _time_multiplier;
const unsigned int _common_output_divisor;
// fundamental creator-specified properties // fundamental creator-specified properties
unsigned int _cycles_per_line; unsigned int _cycles_per_line;

View File

@ -375,9 +375,10 @@ void CRT::prepare_shader()
glUniform2f(positionConversionUniform, _horizontal_flywheel->get_scan_period(), _vertical_flywheel->get_scan_period() / (unsigned int)_vertical_flywheel_output_divider); 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_angle = atan2f(1.0f / (float)_height_of_display, 1.0f);
float scan_normal[] = { sinf(scan_angle), cosf(scan_angle)}; float scan_normal[] = { sinf(scan_angle), -cosf(scan_angle)};
scan_normal[0] /= (float)_height_of_display; float multiplier = (float)_horizontal_flywheel->get_standard_period() / ((float)_height_of_display * (float)_horizontal_flywheel->get_scan_period());
scan_normal[1] /= (float)_height_of_display; scan_normal[0] *= multiplier;
scan_normal[1] *= multiplier;
glUniform2f(scanNormalUniform, scan_normal[0], scan_normal[1]); glUniform2f(scanNormalUniform, scan_normal[0], scan_normal[1]);
} }

View File

@ -160,13 +160,21 @@ struct Flywheel
} }
/*! /*!
@returns the expected length of the scan period. @returns the expected length of the scan period (excluding retrace).
*/ */
inline unsigned int get_scan_period() inline unsigned int get_scan_period()
{ {
return _standard_period - _retrace_time; return _standard_period - _retrace_time;
} }
/*!
@returns the expected length of a complete scan and retrace cycle.
*/
inline unsigned int get_standard_period()
{
return _standard_period;
}
/*! /*!
@returns the number of synchronisation events that have seemed surprising since the last time this method was called; @returns the number of synchronisation events that have seemed surprising since the last time this method was called;
a low number indicates good synchronisation. a low number indicates good synchronisation.