1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-02-23 03:29:04 +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_cycles_per_line,
1024,
1,
Outputs::Display::Type::PAL50,
Outputs::Display::ScanTarget::Modals::DataType::Red1Green1Blue1,
scan_target));

View File

@ -23,7 +23,7 @@ const std::size_t StandardAllocationSize = 320;
}
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,

View File

@ -75,7 +75,9 @@ struct ActivityObserver: public Activity::Observer {
class ScanTarget: public Outputs::Display::ScanTarget {
public:
void set_modals(Modals) {}
void set_modals(Modals m) {
modals_ = m;
}
Scan *get_scan() {
scans_.emplace_back();
@ -94,6 +96,7 @@ class ScanTarget: public Outputs::Display::ScanTarget {
private:
std::vector<Scan> scans_;
std::vector<uint8_t> write_area_;
Modals modals_;
};
@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
// in NTSC and PAL TV."
// time_multiplier_ = IntermediateBufferWidth / cycles_per_line;
time_multiplier_ = 2048 / cycles_per_line; // TODO
time_multiplier_ = 65535 / cycles_per_line;
phase_denominator_ = cycles_per_line * colour_cycle_denominator * time_multiplier_;
phase_numerator_ = 0;
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));
// 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_);
// vertical_flywheel_output_divider_ = static_cast<uint16_t>(ceilf(real_clock_scan_period / 65536.0f) * (time_multiplier_));
// 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_);
const int real_clock_scan_period = multiplied_cycles_per_line * height_of_display;
vertical_flywheel_output_divider_ = (real_clock_scan_period + 65534) / 65535;
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_.composite_colour_space = colour_space;
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) {
switch(displayType) {
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_input_gamma(2.8f);
break;
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_input_gamma(2.2f);
break;
}
}
@ -89,12 +88,12 @@ void CRT::set_composite_function_type(CompositeSourceType type, float offset_of_
}
void CRT::set_input_gamma(float gamma) {
// input_gamma_ = gamma;
// update_gamma();
scan_target_modals_.intended_gamma = gamma;
scan_target_->set_modals(scan_target_modals_);
}
CRT::CRT( int cycles_per_line,
int pixel_clock_least_common_multiple,
int clocks_per_pixel_greatest_common_divisor,
int height_of_display,
Outputs::Display::ColourSpace colour_space,
int colour_cycle_numerator, int colour_cycle_denominator,
@ -104,18 +103,20 @@ CRT::CRT( int cycles_per_line,
Outputs::Display::ScanTarget *scan_target) {
scan_target_ = scan_target;
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);
}
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::ScanTarget::Modals::DataType data_type,
Outputs::Display::ScanTarget *scan_target) {
scan_target_ = scan_target;
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);
}
@ -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(next_scan) {
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].data_offset = static_cast<uint16_t>((total_cycles - number_of_cycles) * number_of_samples / total_cycles);
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.
if(next_scan) {
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].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
std::unique_ptr<Flywheel> horizontal_flywheel_, vertical_flywheel_;
uint16_t vertical_flywheel_output_divider_ = 1;
int vertical_flywheel_output_divider_ = 1;
struct Scan {
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
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
up to the next whole integer.
@ -109,7 +109,7 @@ class CRT {
@see @c set_rgb_sampling_function , @c set_composite_sampling_function
*/
CRT(int cycles_per_line,
int pixel_clock_least_common_multiple,
int minimum_cycles_per_pixel,
int height_of_display,
Outputs::Display::ColourSpace colour_space,
int colour_cycle_numerator,
@ -127,7 +127,7 @@ class CRT {
looked up by display type.
*/
CRT(int cycles_per_line,
int pixel_clock_least_common_multiple,
int minimum_cycles_per_pixel,
Outputs::Display::Type display_type,
Outputs::Display::ScanTarget::Modals::DataType data_type,
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.
ColourSpace composite_colour_space;
/// Nominates a least common multiple of the potential input pixel clocks;
/// if this isn't a crazy number then it'll be used potentially to optimise
/// the composite encoding and decoding process.
int pixel_clock_least_common_multiple;
/// Provides an integral clock rate for the duration of "a single line", specifically
/// for an idealised line. So e.g. in NTSC this will be for the duration of 227.5
/// colour clocks, regardless of whether the source actually stretches lines to
/// 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.
/// This isn't a guarantee, but it should provide a decent-enough estimate.
@ -111,8 +116,13 @@ struct ScanTarget {
/// to contain interesting content.
Rect visible_area;
/// Describes the
/// Describes the usual gamma of the output device these scans would appear on.
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.
@ -130,8 +140,7 @@ struct ScanTarget {
struct Scan {
struct EndPoint {
/// 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
/// extreme right or bottom.
/// numbers, relative to the scale provided in the Modals.
uint16_t x, y;
/// Provides the offset, in samples, into the most recently allocated write area, of data