mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-23 20:29:42 +00:00
Introduced the ability simply to piggy-back off the CRT's natural phase for the colour burst, thereby eliminating a couple of redundant independent attempts in the Oric and Electron.
This commit is contained in:
parent
e359441e2f
commit
a549fd1ecc
@ -60,7 +60,7 @@ Machine::Machine() :
|
||||
void Machine::setup_output(float aspect_ratio)
|
||||
{
|
||||
speaker_.reset(new Speaker);
|
||||
crt_.reset(new Outputs::CRT::CRT(228, 1, 263, Outputs::CRT::ColourSpace::YIQ, 228, 1, 1));
|
||||
crt_.reset(new Outputs::CRT::CRT(228, 1, 263, Outputs::CRT::ColourSpace::YIQ, 228, 1, false, 1));
|
||||
crt_->set_output_device(Outputs::CRT::Television);
|
||||
|
||||
// this is the NTSC phase offset function; see below for PAL
|
||||
@ -93,7 +93,7 @@ void Machine::switch_region()
|
||||
"return mix(float(y) / 14.0, step(4, (iPhase + 2u) & 15u) * cos(phase + phaseOffset), amplitude);"
|
||||
"}");
|
||||
|
||||
crt_->set_new_timing(228, 312, Outputs::CRT::ColourSpace::YUV, 228, 1);
|
||||
crt_->set_new_timing(228, 312, Outputs::CRT::ColourSpace::YUV, 228, 1, true);
|
||||
|
||||
is_pal_region_ = true;
|
||||
speaker_->set_input_rate((float)(get_clock_rate() / 38.0));
|
||||
|
@ -43,8 +43,7 @@ Machine::Machine() :
|
||||
display_output_position_(0),
|
||||
audio_output_position_(0),
|
||||
current_pixel_line_(-1),
|
||||
use_fast_tape_hack_(false),
|
||||
phase_(0)
|
||||
use_fast_tape_hack_(false)
|
||||
{
|
||||
memset(key_states_, 0, sizeof(key_states_));
|
||||
memset(palette_, 0xf, sizeof(palette_));
|
||||
@ -452,8 +451,6 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin
|
||||
|
||||
frame_cycles_ += cycles;
|
||||
|
||||
if(!(frame_cycles_&127)) phase_ += 64;
|
||||
|
||||
// deal with frame wraparound by updating the two dependent subsystems
|
||||
// as though the exact end of frame had been hit, then reset those
|
||||
// and allow the frame cycle counter to assume its real value
|
||||
@ -874,7 +871,7 @@ inline void Machine::update_display()
|
||||
if(this_cycle < 24)
|
||||
{
|
||||
if(final_cycle < 24) return;
|
||||
crt_->output_colour_burst((24-9) * crt_cycles_multiplier, phase_, 12);
|
||||
crt_->output_default_colour_burst((24-9) * crt_cycles_multiplier);
|
||||
display_output_position_ += 24-9;
|
||||
this_cycle = 24;
|
||||
// TODO: phase shouldn't be zero on every line
|
||||
|
@ -135,7 +135,6 @@ class Machine:
|
||||
// Counters related to simultaneous subsystems
|
||||
unsigned int frame_cycles_, display_output_position_;
|
||||
unsigned int audio_output_position_, audio_output_position_error_;
|
||||
uint8_t phase_;
|
||||
|
||||
struct {
|
||||
uint16_t forty1bpp[256];
|
||||
|
@ -24,7 +24,6 @@ VideoOutput::VideoOutput(uint8_t *memory) :
|
||||
frame_counter_(0), counter_(0),
|
||||
is_graphics_mode_(false),
|
||||
character_set_base_address_(0xb400),
|
||||
phase_(0),
|
||||
v_sync_start_position_(PAL50VSyncStartPosition), v_sync_end_position_(PAL50VSyncEndPosition),
|
||||
counter_period_(PAL50Period), next_frame_is_sixty_hertz_(false),
|
||||
crt_(new Outputs::CRT::CRT(64*6, 6, Outputs::CRT::DisplayType::PAL50, 2))
|
||||
@ -95,12 +94,10 @@ void VideoOutput::run_for_cycles(int number_of_cycles)
|
||||
paper_ = 0x00;
|
||||
use_alternative_character_set_ = use_double_height_characters_ = blink_text_ = false;
|
||||
set_character_set_base_address();
|
||||
phase_ += 64;
|
||||
pixel_target_ = (uint16_t *)crt_->allocate_write_area(240);
|
||||
|
||||
if(!counter_)
|
||||
{
|
||||
phase_ += 3; // TODO: incorporate all the lines that were missed
|
||||
frame_counter_++;
|
||||
|
||||
v_sync_start_position_ = next_frame_is_sixty_hertz_ ? PAL60VSyncStartPosition : PAL50VSyncStartPosition;
|
||||
@ -228,7 +225,7 @@ void VideoOutput::run_for_cycles(int number_of_cycles)
|
||||
else if(h_counter < 56)
|
||||
{
|
||||
cycles_run_for = 56 - h_counter;
|
||||
clamp(crt_->output_colour_burst(2 * 6, phase_, 128));
|
||||
clamp(crt_->output_default_colour_burst(2 * 6));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -43,8 +43,6 @@ class VideoOutput {
|
||||
bool use_alternative_character_set_;
|
||||
bool use_double_height_characters_;
|
||||
bool blink_text_;
|
||||
|
||||
uint8_t phase_;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
using namespace Outputs::CRT;
|
||||
|
||||
void CRT::set_new_timing(unsigned int cycles_per_line, unsigned int height_of_display, ColourSpace colour_space, unsigned int colour_cycle_numerator, unsigned int colour_cycle_denominator)
|
||||
void CRT::set_new_timing(unsigned int cycles_per_line, unsigned int height_of_display, ColourSpace colour_space, unsigned int colour_cycle_numerator, unsigned int colour_cycle_denominator, bool should_alternate)
|
||||
{
|
||||
openGL_output_builder_.set_colour_format(colour_space, colour_cycle_numerator, colour_cycle_denominator);
|
||||
|
||||
@ -29,6 +29,11 @@ void CRT::set_new_timing(unsigned int cycles_per_line, unsigned int height_of_di
|
||||
// for horizontal retrace and 500 to 750 µs for vertical retrace in NTSC and PAL TV."
|
||||
|
||||
time_multiplier_ = IntermediateBufferWidth / cycles_per_line;
|
||||
phase_denominator_ = cycles_per_line * colour_cycle_denominator;
|
||||
phase_numerator_ = 0;
|
||||
colour_cycle_numerator_ = colour_cycle_numerator * time_multiplier_;
|
||||
phase_alternates_ = should_alternate;
|
||||
is_alernate_line_ &= phase_alternates_;
|
||||
unsigned int multiplied_cycles_per_line = cycles_per_line * time_multiplier_;
|
||||
|
||||
// generate timing values implied by the given arbuments
|
||||
@ -50,11 +55,11 @@ void CRT::set_new_display_type(unsigned int cycles_per_line, DisplayType display
|
||||
switch(displayType)
|
||||
{
|
||||
case DisplayType::PAL50:
|
||||
set_new_timing(cycles_per_line, 312, ColourSpace::YUV, 709379, 2500); // i.e. 283.7516
|
||||
set_new_timing(cycles_per_line, 312, ColourSpace::YUV, 709379, 2500, true); // i.e. 283.7516
|
||||
break;
|
||||
|
||||
case DisplayType::NTSC60:
|
||||
set_new_timing(cycles_per_line, 262, ColourSpace::YIQ, 545, 2);
|
||||
set_new_timing(cycles_per_line, 262, ColourSpace::YIQ, 545, 2, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -67,12 +72,13 @@ CRT::CRT(unsigned int common_output_divisor, unsigned int buffer_depth) :
|
||||
is_writing_composite_run_(false),
|
||||
delegate_(nullptr),
|
||||
frames_since_last_delegate_call_(0),
|
||||
openGL_output_builder_(buffer_depth) {}
|
||||
openGL_output_builder_(buffer_depth),
|
||||
is_alernate_line_(false) {}
|
||||
|
||||
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 buffer_depth) :
|
||||
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, bool should_alternate, unsigned int buffer_depth) :
|
||||
CRT(common_output_divisor, buffer_depth)
|
||||
{
|
||||
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, should_alternate);
|
||||
}
|
||||
|
||||
CRT::CRT(unsigned int cycles_per_line, unsigned int common_output_divisor, DisplayType displayType, unsigned int buffer_depth) :
|
||||
@ -124,6 +130,8 @@ void CRT::advance_cycles(unsigned int number_of_cycles, bool hsync_requested, bo
|
||||
// get the next sync event and its timing; hsync request is instantaneous (being edge triggered) so
|
||||
// set it to false for the next run through this loop (if any)
|
||||
unsigned int next_run_length = std::min(time_until_vertical_sync_event, time_until_horizontal_sync_event);
|
||||
phase_numerator_ += next_run_length * colour_cycle_numerator_;
|
||||
phase_numerator_ %= phase_denominator_;
|
||||
|
||||
hsync_requested = false;
|
||||
vsync_requested = false;
|
||||
@ -171,6 +179,8 @@ void CRT::advance_cycles(unsigned int number_of_cycles, bool hsync_requested, bo
|
||||
(honoured_event == Flywheel::SyncEvent::StartRetrace && is_writing_composite_run_) ||
|
||||
(honoured_event == Flywheel::SyncEvent::EndRetrace && !horizontal_flywheel_->is_in_retrace() && !vertical_flywheel_->is_in_retrace());
|
||||
|
||||
if(next_run_length == time_until_horizontal_sync_event && next_horizontal_sync_event == Flywheel::SyncEvent::StartRetrace) is_alernate_line_ ^= phase_alternates_;
|
||||
|
||||
if(needs_endpoint)
|
||||
{
|
||||
if(
|
||||
@ -329,6 +339,17 @@ void CRT::output_colour_burst(unsigned int number_of_cycles, uint8_t phase, uint
|
||||
output_scan(&scan);
|
||||
}
|
||||
|
||||
void CRT::output_default_colour_burst(unsigned int number_of_cycles)
|
||||
{
|
||||
Scan scan {
|
||||
.type = Scan::Type::ColourBurst,
|
||||
.number_of_cycles = number_of_cycles,
|
||||
.phase = (uint8_t)((phase_numerator_ * 255) / phase_denominator_ + (is_alernate_line_ ? 128 : 0)),
|
||||
.amplitude = 32
|
||||
};
|
||||
output_scan(&scan);
|
||||
}
|
||||
|
||||
void CRT::output_data(unsigned int number_of_cycles, unsigned int source_divider)
|
||||
{
|
||||
openGL_output_builder_.texture_builder.reduce_previous_allocation_to(number_of_cycles / source_divider);
|
||||
|
@ -46,7 +46,6 @@ class CRT {
|
||||
int sync_capacitor_charge_threshold_; // this charges up during times of sync and depletes otherwise; needs to hit a required threshold to trigger a vertical sync
|
||||
unsigned int sync_period_;
|
||||
|
||||
// each call to output_* generates a scan. A two-slot queue for scans allows edge extensions.
|
||||
struct Scan {
|
||||
enum Type {
|
||||
Sync, Level, Data, Blank, ColourBurst
|
||||
@ -64,6 +63,9 @@ class CRT {
|
||||
uint16_t colour_burst_time_;
|
||||
bool is_writing_composite_run_;
|
||||
|
||||
unsigned int phase_denominator_, phase_numerator_, colour_cycle_numerator_;
|
||||
bool is_alernate_line_, phase_alternates_;
|
||||
|
||||
// the outer entry point for dispatching output_sync, output_blank, output_level and output_data
|
||||
void advance_cycles(unsigned int number_of_cycles, bool hsync_requested, bool vsync_requested, const bool vsync_charging, const Scan::Type type);
|
||||
|
||||
@ -91,7 +93,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 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
|
||||
@ -113,7 +115,7 @@ class CRT {
|
||||
|
||||
@see @c set_rgb_sampling_function , @c set_composite_sampling_function
|
||||
*/
|
||||
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 buffer_depth);
|
||||
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, bool should_alternate, unsigned int buffer_depth);
|
||||
|
||||
/*! 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
|
||||
@ -126,7 +128,7 @@ class CRT {
|
||||
|
||||
/*! Resets the CRT with new timing information. The CRT then continues as though the new timing had
|
||||
been provided at construction. */
|
||||
void set_new_timing(unsigned int cycles_per_line, unsigned int height_of_display, ColourSpace colour_space, unsigned int colour_cycle_numerator, unsigned int colour_cycle_denominator);
|
||||
void set_new_timing(unsigned int cycles_per_line, unsigned int height_of_display, ColourSpace colour_space, unsigned int colour_cycle_numerator, unsigned int colour_cycle_denominator, bool should_alternate);
|
||||
|
||||
/*! Resets the CRT with new timing information derived from a new display type. The CRT then continues
|
||||
as though the new timing had been provided at construction. */
|
||||
@ -175,6 +177,12 @@ class CRT {
|
||||
*/
|
||||
void output_colour_burst(unsigned int number_of_cycles, uint8_t phase, uint8_t amplitude);
|
||||
|
||||
/*! Outputs a colour burst exactly in phase with CRT expectations using the idiomatic amplitude.
|
||||
|
||||
@param number_of_cycles The length of the colour burst;
|
||||
*/
|
||||
void output_default_colour_burst(unsigned int number_of_cycles);
|
||||
|
||||
/*! Attempts to allocate the given number of output samples for writing.
|
||||
|
||||
The beginning of the most recently allocated area is used as the start
|
||||
|
Loading…
Reference in New Issue
Block a user