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