mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-26 09:29:45 +00:00
Removes the CRT requirement for an integral relationship between cycles and samples.
This commit is contained in:
parent
6a79ce9eb1
commit
1c605d58e3
@ -287,7 +287,7 @@ template <class BusHandler> class MOS6560 {
|
||||
case State::Sync: crt_->output_sync(cycles_in_state_ * 4); break;
|
||||
case State::ColourBurst: crt_->output_colour_burst(cycles_in_state_ * 4, (is_odd_frame_ || is_odd_line_) ? 128 : 0); break;
|
||||
case State::Border: output_border(cycles_in_state_ * 4); break;
|
||||
case State::Pixels: crt_->output_data(cycles_in_state_ * 4, 1); break;
|
||||
case State::Pixels: crt_->output_data(cycles_in_state_ * 4); break;
|
||||
}
|
||||
output_state_ = this_state_;
|
||||
cycles_in_state_ = 0;
|
||||
|
@ -536,7 +536,8 @@ void TMS9918::run_for(const HalfCycles cycles) {
|
||||
}
|
||||
|
||||
if(output_column_ == first_right_border_column_) {
|
||||
crt_->output_data(static_cast<unsigned int>(first_right_border_column_ - first_pixel_column_) * 4, 4);
|
||||
const unsigned int data_length = static_cast<unsigned int>(first_right_border_column_ - first_pixel_column_);
|
||||
crt_->output_data(data_length * 4, data_length);
|
||||
pixel_target_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
@ -203,7 +203,7 @@ class CRTCBusHandler {
|
||||
} else {
|
||||
if(was_enabled_) {
|
||||
if(cycles_) {
|
||||
crt_->output_data(cycles_ * 16, pixel_divider_);
|
||||
crt_->output_data(cycles_ * 16, cycles_ * 16 / pixel_divider_);
|
||||
pixel_pointer_ = pixel_data_ = nullptr;
|
||||
}
|
||||
} else {
|
||||
@ -267,7 +267,7 @@ class CRTCBusHandler {
|
||||
// widths so it's not necessarily possible to predict the correct number in advance
|
||||
// and using the upper bound could lead to inefficient behaviour
|
||||
if(pixel_pointer_ == pixel_data_ + 320) {
|
||||
crt_->output_data(cycles_ * 16, pixel_divider_);
|
||||
crt_->output_data(cycles_ * 16, cycles_ * 16 / pixel_divider_);
|
||||
pixel_pointer_ = pixel_data_ = nullptr;
|
||||
cycles_ = 0;
|
||||
}
|
||||
|
@ -38,9 +38,14 @@ template <class BusHandler> class Video {
|
||||
// "uint texValue = texture(sampler, coordinate).r;"
|
||||
// "texValue <<= int(icoordinate.x * 8) & 7;"
|
||||
// "return float(texValue & 128u);"
|
||||
|
||||
"uint texValue = texture(sampler, coordinate).r;"
|
||||
"texValue <<= uint(icoordinate.x * 7.0) % 7u;"
|
||||
"return float(texValue & 64u);"
|
||||
|
||||
// "uint texValue = texture(sampler, coordinate).r;"
|
||||
// "texValue <<= uint(mod(icoordinate.x, 1.0) * 7.0);"
|
||||
// "return float(texValue & 64u);"
|
||||
"}");
|
||||
|
||||
// TODO: the above has precision issues. Fix!
|
||||
@ -91,7 +96,7 @@ template <class BusHandler> class Video {
|
||||
const int pixel_end = std::min(40, ending_column);
|
||||
const int character_row = row_ >> 3;
|
||||
const int pixel_row = row_ & 7;
|
||||
const uint16_t line_address = static_cast<uint16_t>(0x400 + (character_row >> 3) * 40 + ((character_row&7) << 7));
|
||||
const uint16_t line_address = static_cast<uint16_t>(0x400 + (video_page_ * 0x400) + (character_row >> 3) * 40 + ((character_row&7) << 7));
|
||||
|
||||
for(int c = column_; c < pixel_end; ++c) {
|
||||
const uint16_t address = static_cast<uint16_t>(line_address + c);
|
||||
@ -102,8 +107,10 @@ template <class BusHandler> class Video {
|
||||
pixel_pointer_[c] = character_rom_[character_address] ^ ((character & 0x80) ? 0x00 : 0xff);
|
||||
}
|
||||
|
||||
// TODO: graphics; 0x2000+ for high resolution
|
||||
|
||||
if(ending_column >= 40) {
|
||||
crt_->output_data(280, 7);
|
||||
crt_->output_data(280, 40);
|
||||
}
|
||||
} else {
|
||||
if(ending_column >= 40) {
|
||||
@ -163,6 +170,7 @@ template <class BusHandler> class Video {
|
||||
}
|
||||
|
||||
void set_video_page(int page) {
|
||||
video_page_ = page;
|
||||
printf("Video page: %d\n", page);
|
||||
}
|
||||
|
||||
|
@ -437,7 +437,10 @@ void TIA::output_for_cycles(int number_of_cycles) {
|
||||
if(output_mode_ & blank_flag) {
|
||||
if(pixel_target_) {
|
||||
output_pixels(pixels_start_location_, output_cursor);
|
||||
if(crt_) crt_->output_data(static_cast<unsigned int>(output_cursor - pixels_start_location_) * 2, 2);
|
||||
if(crt_) {
|
||||
const unsigned int data_length = static_cast<unsigned int>(output_cursor - pixels_start_location_);
|
||||
crt_->output_data(data_length * 2, data_length);
|
||||
}
|
||||
pixel_target_ = nullptr;
|
||||
pixels_start_location_ = 0;
|
||||
}
|
||||
@ -459,7 +462,8 @@ void TIA::output_for_cycles(int number_of_cycles) {
|
||||
}
|
||||
|
||||
if(horizontal_counter_ == cycles_per_line && crt_) {
|
||||
crt_->output_data(static_cast<unsigned int>(output_cursor - pixels_start_location_) * 2, 2);
|
||||
const unsigned int data_length = static_cast<unsigned int>(output_cursor - pixels_start_location_);
|
||||
crt_->output_data(data_length * 2, data_length);
|
||||
pixel_target_ = nullptr;
|
||||
pixels_start_location_ = 0;
|
||||
}
|
||||
|
@ -97,7 +97,10 @@ void VideoOutput::start_pixel_line() {
|
||||
}
|
||||
|
||||
void VideoOutput::end_pixel_line() {
|
||||
if(current_output_target_) crt_->output_data(static_cast<unsigned int>((current_output_target_ - initial_output_target_) * current_output_divider_), current_output_divider_);
|
||||
if(current_output_target_) {
|
||||
const unsigned int data_length = static_cast<unsigned int>(current_output_target_ - initial_output_target_);
|
||||
crt_->output_data(data_length * current_output_divider_, data_length);
|
||||
}
|
||||
current_character_row_++;
|
||||
}
|
||||
|
||||
@ -115,7 +118,10 @@ void VideoOutput::output_pixels(unsigned int number_of_cycles) {
|
||||
}
|
||||
|
||||
if(!initial_output_target_ || divider != current_output_divider_) {
|
||||
if(current_output_target_) crt_->output_data(static_cast<unsigned int>((current_output_target_ - initial_output_target_) * current_output_divider_), current_output_divider_);
|
||||
if(current_output_target_) {
|
||||
const unsigned int data_length = static_cast<unsigned int>(current_output_target_ - initial_output_target_);
|
||||
crt_->output_data(data_length * current_output_divider_, data_length);
|
||||
}
|
||||
current_output_divider_ = divider;
|
||||
initial_output_target_ = current_output_target_ = crt_->allocate_write_area(640 / current_output_divider_, 4);
|
||||
}
|
||||
|
@ -191,7 +191,7 @@ void VideoOutput::run_for(const Cycles cycles) {
|
||||
}
|
||||
|
||||
if(h_counter == 40) {
|
||||
crt_->output_data(40 * 6, 1);
|
||||
crt_->output_data(40 * 6);
|
||||
}
|
||||
} else {
|
||||
// this is a blank line (or the equivalent part of a pixel line)
|
||||
|
@ -62,7 +62,7 @@ void Video::flush(bool next_sync) {
|
||||
unsigned int data_length = static_cast<unsigned int>(line_data_pointer_ - line_data_) * HalfCyclesPerByte;
|
||||
if(data_length < cycles_since_update_ || next_sync) {
|
||||
unsigned int output_length = std::min(data_length, cycles_since_update_);
|
||||
crt_->output_data(output_length, HalfCyclesPerByte);
|
||||
crt_->output_data(output_length, output_length / HalfCyclesPerByte);
|
||||
line_data_pointer_ = line_data_ = nullptr;
|
||||
cycles_since_update_ -= output_length;
|
||||
} else return;
|
||||
@ -100,7 +100,7 @@ void Video::output_byte(uint8_t byte) {
|
||||
if(line_data_) {
|
||||
// If the buffer is full, output it now and obtain a new one
|
||||
if(line_data_pointer_ - line_data_ == StandardAllocationSize) {
|
||||
crt_->output_data(StandardAllocationSize, HalfCyclesPerByte);
|
||||
crt_->output_data(StandardAllocationSize * HalfCyclesPerByte, StandardAllocationSize);
|
||||
cycles_since_update_ -= StandardAllocationSize * HalfCyclesPerByte;
|
||||
line_data_pointer_ = line_data_ = crt_->allocate_write_area(StandardAllocationSize);
|
||||
if(!line_data_) return;
|
||||
|
@ -125,11 +125,8 @@ Flywheel::SyncEvent CRT::get_next_horizontal_sync_event(bool hsync_is_requested,
|
||||
#define output_position_y() (*reinterpret_cast<uint16_t *>(&next_output_run[OutputVertexOffsetOfVertical + 0]))
|
||||
#define output_tex_y() (*reinterpret_cast<uint16_t *>(&next_output_run[OutputVertexOffsetOfVertical + 2]))
|
||||
|
||||
#define source_input_position_x1() (*reinterpret_cast<uint16_t *>(&next_run[SourceVertexOffsetOfInputStart + 0]))
|
||||
#define source_input_position_y() (*reinterpret_cast<uint16_t *>(&next_run[SourceVertexOffsetOfInputStart + 2]))
|
||||
#define source_input_position_x2() (*reinterpret_cast<uint16_t *>(&next_run[SourceVertexOffsetOfEnds + 0]))
|
||||
#define source_output_position_x1() (*reinterpret_cast<uint16_t *>(&next_run[SourceVertexOffsetOfOutputStart + 0]))
|
||||
#define source_output_position_y() (*reinterpret_cast<uint16_t *>(&next_run[SourceVertexOffsetOfOutputStart + 2]))
|
||||
#define source_output_position_x2() (*reinterpret_cast<uint16_t *>(&next_run[SourceVertexOffsetOfEnds + 2]))
|
||||
#define source_phase() next_run[SourceVertexOffsetOfPhaseTimeAndAmplitude + 0]
|
||||
#define source_amplitude() next_run[SourceVertexOffsetOfPhaseTimeAndAmplitude + 1]
|
||||
@ -217,6 +214,9 @@ void CRT::advance_cycles(unsigned int number_of_cycles, bool hsync_requested, bo
|
||||
output_tex_y() = output_y;
|
||||
output_x2() = static_cast<uint16_t>(horizontal_flywheel_->get_current_output_position());
|
||||
}
|
||||
|
||||
// TODO: below I've assumed a one-to-one correspondance with output runs and input data; that's
|
||||
// obviously not completely sustainable. It's a latent bug.
|
||||
openGL_output_builder_.array_builder.flush(
|
||||
[=] (uint8_t *input_buffer, std::size_t input_size, uint8_t *output_buffer, std::size_t output_size) {
|
||||
openGL_output_builder_.texture_builder.flush(
|
||||
@ -264,15 +264,11 @@ void CRT::advance_cycles(unsigned int number_of_cycles, bool hsync_requested, bo
|
||||
#undef output_position_y
|
||||
#undef output_tex_y
|
||||
|
||||
#undef source_input_position_x1
|
||||
#undef source_input_position_y
|
||||
#undef source_input_position_x2
|
||||
#undef source_output_position_x1
|
||||
#undef source_output_position_y
|
||||
#undef source_output_position_x2
|
||||
#undef source_phase
|
||||
#undef source_amplitude
|
||||
#undef source_phase_time
|
||||
|
||||
// MARK: - stream feeding methods
|
||||
|
||||
@ -384,8 +380,8 @@ void CRT::set_immediate_default_phase(float phase) {
|
||||
phase_numerator_ = static_cast<unsigned int>(phase * static_cast<float>(phase_denominator_));
|
||||
}
|
||||
|
||||
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);
|
||||
void CRT::output_data(unsigned int number_of_cycles, unsigned int number_of_samples) {
|
||||
openGL_output_builder_.texture_builder.reduce_previous_allocation_to(number_of_samples);
|
||||
Scan scan;
|
||||
scan.type = Scan::Type::Data;
|
||||
scan.number_of_cycles = number_of_cycles;
|
||||
|
@ -180,17 +180,21 @@ class CRT {
|
||||
void output_level(unsigned int number_of_cycles);
|
||||
|
||||
/*! Declares that the caller has created a run of data via @c allocate_write_area and @c get_write_target_for_buffer
|
||||
that is at least @c number_of_cycles long, and that the first @c number_of_cycles/source_divider should be spread
|
||||
over that amount of time.
|
||||
that is at least @c number_of_samples long, and that the first @c number_of_samples should be spread
|
||||
over @c number_of_cycles.
|
||||
|
||||
@param number_of_cycles The amount of data to output.
|
||||
|
||||
@param source_divider A divider for source data; if the divider is 1 then one source pixel is output every cycle,
|
||||
if it is 2 then one source pixel covers two cycles; if it is n then one source pixel covers n cycles.
|
||||
@param number_of_samples The number of samples of input data to output.
|
||||
|
||||
@see @c allocate_write_area , @c get_write_target_for_buffer
|
||||
*/
|
||||
void output_data(unsigned int number_of_cycles, unsigned int source_divider);
|
||||
void output_data(unsigned int number_of_cycles, unsigned int number_of_samples);
|
||||
|
||||
/*! A shorthand form for output_data that assumes the number of cycles to output for is the same as the number of samples. */
|
||||
void output_data(unsigned int number_of_cycles) {
|
||||
output_data(number_of_cycles, number_of_cycles);
|
||||
}
|
||||
|
||||
/*! Outputs a colour burst.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user