1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-12-24 12:30:17 +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},
_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(
"float sample(vec2 coordinate, float phase)\n"
"{\n"

View File

@ -32,7 +32,7 @@ Machine::Machine() :
_audioOutputPositionError(0),
_currentOutputLine(0),
_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(
"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));
// 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)
@ -74,14 +75,15 @@ void CRT::allocate_buffers(unsigned int number, va_list sizes)
va_end(va);
}
CRT::CRT() :
CRT::CRT(unsigned int common_output_divisor) :
_next_scan(0),
_run_write_pointer(0),
_sync_capacitor_charge_level(0),
_is_receiving_sync(false),
_output_mutex(new std::mutex),
_visible_area(Rect(0, 0, 1, 1)),
_sync_period(0)
_sync_period(0),
_common_output_divisor(common_output_divisor)
{
construct_openGL();
}
@ -96,7 +98,7 @@ CRT::~CRT()
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);
@ -106,7 +108,7 @@ CRT::CRT(unsigned int cycles_per_line, unsigned int height_of_display, ColourSpa
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);

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
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
up to the next whole integer.
@ -79,7 +84,7 @@ class CRT {
@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
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
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
been provided at construction. */
@ -232,12 +237,13 @@ class CRT {
#endif
private:
CRT();
CRT(unsigned int common_output_divisor);
void allocate_buffers(unsigned int number, va_list sizes);
// the incoming clock lengths will be multiplied by something to give at least 1000
// sample points per line
unsigned int _time_multiplier;
const unsigned int _common_output_divisor;
// fundamental creator-specified properties
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);
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;
float scan_normal[] = { sinf(scan_angle), -cosf(scan_angle)};
float multiplier = (float)_horizontal_flywheel->get_standard_period() / ((float)_height_of_display * (float)_horizontal_flywheel->get_scan_period());
scan_normal[0] *= multiplier;
scan_normal[1] *= multiplier;
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()
{
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;
a low number indicates good synchronisation.