1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-08-08 14:25:05 +00:00

Ensures scan positions are communicated with a specified range, and switches manner of pixel clock communication.

This commit is contained in:
Thomas Harte
2018-11-04 21:06:25 -05:00
parent 0446e350d3
commit 014da41471
6 changed files with 43 additions and 30 deletions

View File

@@ -45,7 +45,7 @@ VideoOutput::VideoOutput(uint8_t *memory, Outputs::Display::ScanTarget *scan_tar
crt_.reset(new Outputs::CRT::CRT( crt_.reset(new Outputs::CRT::CRT(
crt_cycles_per_line, crt_cycles_per_line,
1024, 1,
Outputs::Display::Type::PAL50, Outputs::Display::Type::PAL50,
Outputs::Display::ScanTarget::Modals::DataType::Red1Green1Blue1, Outputs::Display::ScanTarget::Modals::DataType::Red1Green1Blue1,
scan_target)); scan_target));

View File

@@ -23,7 +23,7 @@ const std::size_t StandardAllocationSize = 320;
} }
Video::Video(Outputs::Display::ScanTarget *scan_target) : Video::Video(Outputs::Display::ScanTarget *scan_target) :
crt_(new Outputs::CRT::CRT(207 * 2, 414, Outputs::Display::Type::PAL50, Outputs::Display::ScanTarget::Modals::DataType::Luminance1, scan_target)) crt_(new Outputs::CRT::CRT(207 * 2, 1, Outputs::Display::Type::PAL50, Outputs::Display::ScanTarget::Modals::DataType::Luminance1, scan_target))
{ {
// Set a composite sampling function that assumes two-level input; either a byte is 0, which is black, // Set a composite sampling function that assumes two-level input; either a byte is 0, which is black,

View File

@@ -75,7 +75,9 @@ struct ActivityObserver: public Activity::Observer {
class ScanTarget: public Outputs::Display::ScanTarget { class ScanTarget: public Outputs::Display::ScanTarget {
public: public:
void set_modals(Modals) {} void set_modals(Modals m) {
modals_ = m;
}
Scan *get_scan() { Scan *get_scan() {
scans_.emplace_back(); scans_.emplace_back();
@@ -94,6 +96,7 @@ class ScanTarget: public Outputs::Display::ScanTarget {
private: private:
std::vector<Scan> scans_; std::vector<Scan> scans_;
std::vector<uint8_t> write_area_; std::vector<uint8_t> write_area_;
Modals modals_;
}; };
@implementation CSMachine { @implementation CSMachine {

View File

@@ -28,8 +28,7 @@ void CRT::set_new_timing(int cycles_per_line, int height_of_display, Outputs::Di
// 7 microseconds for horizontal retrace and 500 to 750 microseconds for vertical retrace // 7 microseconds for horizontal retrace and 500 to 750 microseconds for vertical retrace
// in NTSC and PAL TV." // in NTSC and PAL TV."
// time_multiplier_ = IntermediateBufferWidth / cycles_per_line; time_multiplier_ = 65535 / cycles_per_line;
time_multiplier_ = 2048 / cycles_per_line; // TODO
phase_denominator_ = cycles_per_line * colour_cycle_denominator * time_multiplier_; phase_denominator_ = cycles_per_line * colour_cycle_denominator * time_multiplier_;
phase_numerator_ = 0; phase_numerator_ = 0;
colour_cycle_numerator_ = colour_cycle_numerator; colour_cycle_numerator_ = colour_cycle_numerator;
@@ -56,11 +55,11 @@ void CRT::set_new_timing(int cycles_per_line, int height_of_display, Outputs::Di
vertical_flywheel_.reset(new Flywheel(multiplied_cycles_per_line * height_of_display, scanlinesVerticalRetraceTime * multiplied_cycles_per_line, (multiplied_cycles_per_line * height_of_display) >> 3)); vertical_flywheel_.reset(new Flywheel(multiplied_cycles_per_line * height_of_display, scanlinesVerticalRetraceTime * multiplied_cycles_per_line, (multiplied_cycles_per_line * height_of_display) >> 3));
// 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
// const int real_clock_scan_period = (multiplied_cycles_per_line * height_of_display) / (time_multiplier_); const int real_clock_scan_period = multiplied_cycles_per_line * height_of_display;
// vertical_flywheel_output_divider_ = static_cast<uint16_t>(ceilf(real_clock_scan_period / 65536.0f) * (time_multiplier_)); vertical_flywheel_output_divider_ = (real_clock_scan_period + 65534) / 65535;
// openGL_output_builder_.set_timing(cycles_per_line, multiplied_cycles_per_line, height_of_display, horizontal_flywheel_->get_scan_period(), vertical_flywheel_->get_scan_period(), vertical_flywheel_output_divider_);
scan_target_modals_.output_scale.x = uint16_t(time_multiplier_ * cycles_per_line);
scan_target_modals_.output_scale.y = uint16_t((multiplied_cycles_per_line * height_of_display) / vertical_flywheel_output_divider_);
scan_target_modals_.expected_vertical_lines = height_of_display; scan_target_modals_.expected_vertical_lines = height_of_display;
scan_target_modals_.composite_colour_space = colour_space; scan_target_modals_.composite_colour_space = colour_space;
scan_target_->set_modals(scan_target_modals_); scan_target_->set_modals(scan_target_modals_);
@@ -69,13 +68,13 @@ void CRT::set_new_timing(int cycles_per_line, int height_of_display, Outputs::Di
void CRT::set_new_display_type(int cycles_per_line, Outputs::Display::Type displayType) { void CRT::set_new_display_type(int cycles_per_line, Outputs::Display::Type displayType) {
switch(displayType) { switch(displayType) {
case Outputs::Display::Type::PAL50: case Outputs::Display::Type::PAL50:
scan_target_modals_.intended_gamma = 2.8f;
set_new_timing(cycles_per_line, 312, Outputs::Display::ColourSpace::YUV, 709379, 2500, 5, true); // i.e. 283.7516; 2.5 lines = vertical sync set_new_timing(cycles_per_line, 312, Outputs::Display::ColourSpace::YUV, 709379, 2500, 5, true); // i.e. 283.7516; 2.5 lines = vertical sync
set_input_gamma(2.8f);
break; break;
case Outputs::Display::Type::NTSC60: case Outputs::Display::Type::NTSC60:
scan_target_modals_.intended_gamma = 2.2f;
set_new_timing(cycles_per_line, 262, Outputs::Display::ColourSpace::YIQ, 455, 2, 6, false); // i.e. 227.5, 3 lines = vertical sync set_new_timing(cycles_per_line, 262, Outputs::Display::ColourSpace::YIQ, 455, 2, 6, false); // i.e. 227.5, 3 lines = vertical sync
set_input_gamma(2.2f);
break; break;
} }
} }
@@ -89,12 +88,12 @@ void CRT::set_composite_function_type(CompositeSourceType type, float offset_of_
} }
void CRT::set_input_gamma(float gamma) { void CRT::set_input_gamma(float gamma) {
// input_gamma_ = gamma; scan_target_modals_.intended_gamma = gamma;
// update_gamma(); scan_target_->set_modals(scan_target_modals_);
} }
CRT::CRT( int cycles_per_line, CRT::CRT( int cycles_per_line,
int pixel_clock_least_common_multiple, int clocks_per_pixel_greatest_common_divisor,
int height_of_display, int height_of_display,
Outputs::Display::ColourSpace colour_space, Outputs::Display::ColourSpace colour_space,
int colour_cycle_numerator, int colour_cycle_denominator, int colour_cycle_numerator, int colour_cycle_denominator,
@@ -104,18 +103,20 @@ CRT::CRT( int cycles_per_line,
Outputs::Display::ScanTarget *scan_target) { Outputs::Display::ScanTarget *scan_target) {
scan_target_ = scan_target; scan_target_ = scan_target;
scan_target_modals_.source_data_type = data_type; scan_target_modals_.source_data_type = data_type;
scan_target_modals_.pixel_clock_least_common_multiple = pixel_clock_least_common_multiple; scan_target_modals_.cycles_per_line = cycles_per_line;
scan_target_modals_.clocks_per_pixel_greatest_common_divisor = clocks_per_pixel_greatest_common_divisor;
set_new_timing(cycles_per_line, height_of_display, colour_space, colour_cycle_numerator, colour_cycle_denominator, vertical_sync_half_lines, should_alternate); set_new_timing(cycles_per_line, height_of_display, colour_space, colour_cycle_numerator, colour_cycle_denominator, vertical_sync_half_lines, should_alternate);
} }
CRT::CRT( int cycles_per_line, CRT::CRT( int cycles_per_line,
int pixel_clock_least_common_multiple, int clocks_per_pixel_greatest_common_divisor,
Outputs::Display::Type display_type, Outputs::Display::Type display_type,
Outputs::Display::ScanTarget::Modals::DataType data_type, Outputs::Display::ScanTarget::Modals::DataType data_type,
Outputs::Display::ScanTarget *scan_target) { Outputs::Display::ScanTarget *scan_target) {
scan_target_ = scan_target; scan_target_ = scan_target;
scan_target_modals_.source_data_type = data_type; scan_target_modals_.source_data_type = data_type;
scan_target_modals_.pixel_clock_least_common_multiple = pixel_clock_least_common_multiple; scan_target_modals_.cycles_per_line = cycles_per_line;
scan_target_modals_.clocks_per_pixel_greatest_common_divisor = clocks_per_pixel_greatest_common_divisor;
set_new_display_type(cycles_per_line, display_type); set_new_display_type(cycles_per_line, display_type);
} }
@@ -157,7 +158,7 @@ void CRT::advance_cycles(int number_of_cycles, bool hsync_requested, bool vsync_
// If outputting, store the start location and // If outputting, store the start location and
if(next_scan) { if(next_scan) {
next_scan->end_points[0].x = static_cast<uint16_t>(horizontal_flywheel_->get_current_output_position()); next_scan->end_points[0].x = static_cast<uint16_t>(horizontal_flywheel_->get_current_output_position());
next_scan->end_points[0].y = static_cast<uint16_t>(vertical_flywheel_->get_current_output_position()); next_scan->end_points[0].y = static_cast<uint16_t>(vertical_flywheel_->get_current_output_position() / vertical_flywheel_output_divider_);
next_scan->end_points[0].composite_angle = colour_burst_angle_; // TODO. next_scan->end_points[0].composite_angle = colour_burst_angle_; // TODO.
next_scan->end_points[0].data_offset = static_cast<uint16_t>((total_cycles - number_of_cycles) * number_of_samples / total_cycles); next_scan->end_points[0].data_offset = static_cast<uint16_t>((total_cycles - number_of_cycles) * number_of_samples / total_cycles);
next_scan->composite_amplitude = colour_burst_amplitude_; next_scan->composite_amplitude = colour_burst_amplitude_;
@@ -175,7 +176,7 @@ void CRT::advance_cycles(int number_of_cycles, bool hsync_requested, bool vsync_
// Store an endpoint if necessary. // Store an endpoint if necessary.
if(next_scan) { if(next_scan) {
next_scan->end_points[1].x = static_cast<uint16_t>(horizontal_flywheel_->get_current_output_position()); next_scan->end_points[1].x = static_cast<uint16_t>(horizontal_flywheel_->get_current_output_position());
next_scan->end_points[1].y = static_cast<uint16_t>(vertical_flywheel_->get_current_output_position()); next_scan->end_points[1].y = static_cast<uint16_t>(vertical_flywheel_->get_current_output_position() / vertical_flywheel_output_divider_);
next_scan->end_points[1].composite_angle = colour_burst_angle_; // TODO. next_scan->end_points[1].composite_angle = colour_burst_angle_; // TODO.
next_scan->end_points[1].data_offset = static_cast<uint16_t>((total_cycles - number_of_cycles) * number_of_samples / total_cycles); next_scan->end_points[1].data_offset = static_cast<uint16_t>((total_cycles - number_of_cycles) * number_of_samples / total_cycles);
} }

View File

@@ -33,7 +33,7 @@ class CRT {
// the two flywheels regulating scanning // the two flywheels regulating scanning
std::unique_ptr<Flywheel> horizontal_flywheel_, vertical_flywheel_; std::unique_ptr<Flywheel> horizontal_flywheel_, vertical_flywheel_;
uint16_t vertical_flywheel_output_divider_ = 1; int vertical_flywheel_output_divider_ = 1;
struct Scan { struct Scan {
enum Type { enum Type {
@@ -89,7 +89,7 @@ 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 pixel_clock_least_common_multiple TODO. @param minimum_cycles_per_pixel TODO.
@param height_of_display The number of lines that nominally form one field of the display, rounded @param height_of_display 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.
@@ -109,7 +109,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(int cycles_per_line, CRT(int cycles_per_line,
int pixel_clock_least_common_multiple, int minimum_cycles_per_pixel,
int height_of_display, int height_of_display,
Outputs::Display::ColourSpace colour_space, Outputs::Display::ColourSpace colour_space,
int colour_cycle_numerator, int colour_cycle_numerator,
@@ -127,7 +127,7 @@ class CRT {
looked up by display type. looked up by display type.
*/ */
CRT(int cycles_per_line, CRT(int cycles_per_line,
int pixel_clock_least_common_multiple, int minimum_cycles_per_pixel,
Outputs::Display::Type display_type, Outputs::Display::Type display_type,
Outputs::Display::ScanTarget::Modals::DataType data_type, Outputs::Display::ScanTarget::Modals::DataType data_type,
Outputs::Display::ScanTarget *scan_target); Outputs::Display::ScanTarget *scan_target);

View File

@@ -98,10 +98,15 @@ struct ScanTarget {
/// If being fed composite data, this defines the colour space in use. /// If being fed composite data, this defines the colour space in use.
ColourSpace composite_colour_space; ColourSpace composite_colour_space;
/// Nominates a least common multiple of the potential input pixel clocks; /// Provides an integral clock rate for the duration of "a single line", specifically
/// if this isn't a crazy number then it'll be used potentially to optimise /// for an idealised line. So e.g. in NTSC this will be for the duration of 227.5
/// the composite encoding and decoding process. /// colour clocks, regardless of whether the source actually stretches lines to
int pixel_clock_least_common_multiple; /// 228 colour cycles, abbreviates them to 227 colour cycles, etc.
int cycles_per_line;
/// Sets a GCD for the durations of pixels coming out of this device. This with
/// the @c cycles_per_line are offered for sizing of intermediary buffers.
int clocks_per_pixel_greatest_common_divisor;
/// Provides a pre-estimate of the likely number of left-to-right scans per frame. /// Provides a pre-estimate of the likely number of left-to-right scans per frame.
/// This isn't a guarantee, but it should provide a decent-enough estimate. /// This isn't a guarantee, but it should provide a decent-enough estimate.
@@ -111,8 +116,13 @@ struct ScanTarget {
/// to contain interesting content. /// to contain interesting content.
Rect visible_area; Rect visible_area;
/// Describes the /// Describes the usual gamma of the output device these scans would appear on.
float intended_gamma; float intended_gamma;
/// Specifies the range of values that will be output for x and y coordinates.
struct {
uint16_t x, y;
} output_scale;
}; };
/// Sets the total format of input data. /// Sets the total format of input data.
@@ -130,8 +140,7 @@ struct ScanTarget {
struct Scan { struct Scan {
struct EndPoint { struct EndPoint {
/// Provide the coordinate of this endpoint. These are fixed point, purely fractional /// Provide the coordinate of this endpoint. These are fixed point, purely fractional
/// numbers: 0 is the extreme left or top of the scanned rectangle, and 65535 is the /// numbers, relative to the scale provided in the Modals.
/// extreme right or bottom.
uint16_t x, y; uint16_t x, y;
/// Provides the offset, in samples, into the most recently allocated write area, of data /// Provides the offset, in samples, into the most recently allocated write area, of data